Version 1.14.0-dev.2.0
Merge commit '79a8654e5fb30dfce902636961d6a5ffb69e6f85' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5f6d954..087ba19 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,7 @@
* `Base64Decoder.convert` now takes optional `start` and `end` parameters.
* `dart:core`
+ * Added `current` getter to `StackTrace` class.
* Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
return type.
* Added `growable` parameter to `List.filled` constructor.
@@ -18,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
diff --git a/DEPS b/DEPS
index a98a3b5..0ca12c9 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,6 @@
# Revisions of /third_party/* dependencies.
"7zip_rev" : "@19997",
- "analyzer_cli_rev" : "@c93a3d2d1c7715a6c7a067ebdbc9ba716b865226",
"args_tag": "@0.13.0",
"async_tag": "@1.2.0",
"barback_tag" : "@0.15.2+7",
@@ -51,7 +50,7 @@
"crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
"csslib_tag" : "@0.12.0",
"dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
- "dartdoc_rev" : "@18f85ff0b389c417550e541055a84b04273f2b38",
+ "dartdoc_tag" : "@v0.8.3",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.2.0",
"dev_compiler_rev": "@0.1.9",
@@ -68,14 +67,14 @@
"intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@1.1.1",
- "linter_rev": "@74e5478c3693a9dcf05cc99b0dc5d53f0f776375",
+ "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",
@@ -84,7 +83,7 @@
"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",
@@ -172,8 +171,6 @@
(Var("github_mirror") % "dart-services") +
Var("dart_services_rev"),
- Var("dart_root") + "/third_party/pkg/analyzer_cli":
- (Var("github_mirror") % "analyzer_cli") + Var("analyzer_cli_rev"),
Var("dart_root") + "/third_party/pkg/args":
(Var("github_mirror") % "args") + Var("args_tag"),
Var("dart_root") + "/third_party/pkg/async":
@@ -195,7 +192,7 @@
Var("dart_root") + "/third_party/pkg/dart2js_info":
(Var("github_mirror") % "dart2js_info") + Var("dart2js_info_rev"),
Var("dart_root") + "/third_party/pkg/dartdoc":
- (Var("github_mirror") % "dartdoc") + Var("dartdoc_rev"),
+ (Var("github_mirror") % "dartdoc") + Var("dartdoc_tag"),
Var("dart_root") + "/third_party/pkg/dev_compiler":
(Var("github_mirror") % "dev_compiler") + Var("dev_compiler_rev"),
Var("dart_root") + "/third_party/pkg/glob":
@@ -233,7 +230,7 @@
+ "/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":
diff --git a/dart.gyp b/dart.gyp
index 81a8f05..3e73877 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -25,6 +25,7 @@
'type': 'none',
'dependencies': [
'runtime/dart-runtime.gyp:dart',
+ 'runtime/dart-runtime.gyp:dart_precompiled',
'runtime/dart-runtime.gyp:dart_no_snapshot',
'runtime/dart-runtime.gyp:run_vm_tests',
'runtime/dart-runtime.gyp:process_test',
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index eb5f9a9..68947be 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -61,7 +61,7 @@
</style></head>
<body>
<h1>Analysis Server API Specification</h1>
- <h1 style="color:#999999">Version 1.12.0</h1>
+ <h1 style="color:#999999">Version 1.13.0</h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -405,6 +405,7 @@
+
@@ -515,6 +516,46 @@
in multiple contexts in conflicting ways (such as a
part that is included in multiple libraries).
</p>
+ </dd></dl></dd><dt class="request"><a name="request_analysis.getReachableSources">analysis.getReachableSources</a> (<a href="#request_analysis.getReachableSources">#</a>)</dt><dd><div class="box"><pre>request: {
+ "id": String
+ "method": "analysis.getReachableSources"
+ "params": {
+ "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+ }
+}</pre><br><pre>response: {
+ "id": String
+ "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+ "result": {
+ "<b>sources</b>": Map<String, List<String>>
+ }
+}</pre></div>
+ <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>
+
+
+ <h4>Parameters</h4><dl><dt class="field"><b><i>file ( <a href="#type_FilePath">FilePath</a> )</i></b></dt><dd>
+
+ <p>
+ The file for which reachable source information is being requested.
+ </p>
+ </dd></dl><h4>Returns</h4><dl><dt class="field"><b><i>sources ( Map<String, List<String>> )</i></b></dt><dd>
+
+ <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>
</dd></dl></dd><dt class="request"><a name="request_analysis.getLibraryDependencies">analysis.getLibraryDependencies</a> (<a href="#request_analysis.getLibraryDependencies">#</a>)</dt><dd><div class="box"><pre>request: {
"id": String
"method": "analysis.getLibraryDependencies"
@@ -3576,6 +3617,13 @@
which does not match a file currently subject to
analysis.
</p>
+ </dd><dt class="value">GET_REACHABLE_SOURCES_INVALID_FILE</dt><dd>
+
+ <p>
+ An "analysis.getReachableSources" request specified a FilePath
+ which does not match a file currently subject to
+ analysis.
+ </p>
</dd><dt class="value">INVALID_ANALYSIS_ROOT</dt><dd>
<p>
@@ -4253,7 +4301,7 @@
TBD
</p>
<h2 class="domain"><a name="index">Index</a></h2>
- <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+ <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getReachableSources">getReachableSources</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
</body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
index d4903e6..14bdcb3 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_core.dart
@@ -4,6 +4,8 @@
library analysis_server.plugin.edit.assist.assist_core;
+import 'dart:async';
+
import 'package:analysis_server/plugin/protocol/protocol.dart'
show SourceChange;
import 'package:analyzer/src/generated/engine.dart';
@@ -50,19 +52,42 @@
}
/**
+ * An object used to provide context information for [AssistContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class AssistContext {
+ /**
+ * The [AnalysisContext] to get assists in.
+ */
+ AnalysisContext get analysisContext;
+
+ /**
+ * The length of the selection.
+ */
+ int get selectionLength;
+
+ /**
+ * The start of the selection.
+ */
+ int get selectionOffset;
+
+ /**
+ * The source to get assists in.
+ */
+ Source get source;
+}
+
+/**
* An object used to produce assists for a specific location.
*
* Clients may implement this class when implementing plugins.
*/
abstract class AssistContributor {
/**
- * Return a list of assists for a location in the given [source]. The location
- * is specified by the [offset] and [length] of the selected region. The
- * [context] can be used to get additional information that is useful for
- * computing assists.
+ * Completes with a list of assists for the given [context].
*/
- List<Assist> computeAssists(
- AnalysisContext context, Source source, int offset, int length);
+ Future<List<Assist>> computeAssists(AssistContext context);
}
/**
diff --git a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
index ccdc123..2da3812 100644
--- a/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/assist/assist_dart.dart
@@ -4,42 +4,109 @@
library analysis_server.plugin.edit.assist.assist_dart;
+import 'dart:async';
+
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
/**
- * An [AssistContributor] that can be used to contribute assists for Dart
- * files.
+ * An object used to provide context information for [DartAssistContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartAssistContext {
+ /**
+ * The [AnalysisContext] to get assists in.
+ */
+ AnalysisContext get analysisContext;
+
+ /**
+ * The length of the selection.
+ */
+ int get selectionLength;
+
+ /**
+ * The start of the selection.
+ */
+ int get selectionOffset;
+
+ /**
+ * The source to get assists in.
+ */
+ Source get source;
+
+ /**
+ * The [CompilationUnit] to compute assists in.
+ */
+ CompilationUnit get unit;
+}
+
+/**
+ * An [AssistContributor] that can be used to contribute assists for Dart files.
*
* Clients may extend this class when implementing plugins.
*/
abstract class DartAssistContributor implements AssistContributor {
@override
- List<Assist> computeAssists(
- AnalysisContext context, Source source, int offset, int length) {
+ Future<List<Assist>> computeAssists(AssistContext context) async {
+ AnalysisContext analysisContext = context.analysisContext;
+ Source source = context.source;
if (!AnalysisEngine.isDartFileName(source.fullName)) {
return Assist.EMPTY_LIST;
}
- List<Source> libraries = context.getLibrariesContaining(source);
+ List<Source> libraries = analysisContext.getLibrariesContaining(source);
if (libraries.isEmpty) {
return Assist.EMPTY_LIST;
}
CompilationUnit unit =
- context.resolveCompilationUnit2(source, libraries[0]);
+ analysisContext.resolveCompilationUnit2(source, libraries[0]);
if (unit == null) {
return Assist.EMPTY_LIST;
}
- return internalComputeAssists(unit, offset, length);
+ DartAssistContext dartContext = new _DartAssistContextImpl(context, unit);
+ return internalComputeAssists(dartContext);
}
/**
- * Return a list of assists for a location in the given [source]. The location
- * is specified by the [offset] and [length] of the selected region. The
- * [context] can be used to get additional information that is useful for
- * computing assists.
+ * Completes with a list of assists for the given [context].
*/
- List<Assist> internalComputeAssists(
- CompilationUnit unit, int offset, int length);
+ Future<List<Assist>> internalComputeAssists(DartAssistContext context);
+}
+
+/**
+ * The implementation of [DartAssistContext].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class _DartAssistContextImpl implements DartAssistContext {
+ final AssistContext _context;
+
+ /**
+ * The [CompilationUnit] to compute assists in.
+ */
+ final CompilationUnit unit;
+
+ _DartAssistContextImpl(this._context, this.unit);
+
+ /**
+ * The [AnalysisContext] to get assists in.
+ */
+ AnalysisContext get analysisContext => _context.analysisContext;
+
+ /**
+ * The length of the selection.
+ */
+ int get selectionLength => _context.selectionLength;
+
+ /**
+ * The start of the selection.
+ */
+ int get selectionOffset => _context.selectionOffset;
+
+ /**
+ * The source to get assists in.
+ */
+ Source get source => _context.source;
}
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
index 123fa24..0ff626f 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_core.dart
@@ -4,6 +4,8 @@
library analysis_server.plugin.edit.fix.fix_core;
+import 'dart:async';
+
import 'package:analysis_server/plugin/protocol/protocol.dart'
show SourceChange;
import 'package:analyzer/file_system/file_system.dart';
@@ -51,6 +53,28 @@
}
/**
+ * An object used to provide context information for [FixContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class FixContext {
+ /**
+ * The [AnalysisContext] to get fixes in.
+ */
+ AnalysisContext get analysisContext;
+
+ /**
+ * The error to fix, should be reported in the given [analysisContext].
+ */
+ AnalysisError get error;
+
+ /**
+ * The [ResourceProvider] to access files and folders.
+ */
+ ResourceProvider get resourceProvider;
+}
+
+/**
* An object used to produce fixes for a specific error. Fix contributors are
* long-lived objects and must not retain any state between invocations of
* [computeFixes].
@@ -59,11 +83,9 @@
*/
abstract class FixContributor {
/**
- * Return a list of fixes for the given [error]. The error was reported
- * after it's source was analyzed in the given [context].
+ * Return a list of fixes for the given [context].
*/
- List<Fix> computeFixes(ResourceProvider resourceProvider,
- AnalysisContext context, AnalysisError error);
+ Future<List<Fix>> computeFixes(FixContext context);
}
/**
@@ -71,8 +93,8 @@
* information that is common across a number of fixes and to be shared by those
* fixes. For example, if an unnecessary cast is found then one of the suggested
* fixes will be to remove the cast. If there are multiple unnecessary casts in
- * a single file, then there will be multiple fixes, one per occurance, but they
- * will all share the same kind.
+ * a single file, then there will be multiple fixes, one per occurrence, but
+ * they will all share the same kind.
*
* Clients may not extend, implement or mix-in this class.
*/
diff --git a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
index 54baa7c..e8f7104 100644
--- a/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
+++ b/pkg/analysis_server/lib/plugin/edit/fix/fix_dart.dart
@@ -4,14 +4,28 @@
library analysis_server.plugin.edit.fix.fix_dart;
+import 'dart:async';
+
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
-import 'package:analyzer/file_system/file_system.dart';
+import 'package:analysis_server/src/services/correction/fix_internal.dart'
+ show DartFixContextImpl;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/source.dart';
/**
+ * An object used to provide context information for [DartFixContributor]s.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartFixContext implements FixContext {
+ /**
+ * The [CompilationUnit] to compute fixes in.
+ */
+ CompilationUnit get unit;
+}
+
+/**
* A [FixContributor] that can be used to contribute fixes for errors in Dart
* files.
*
@@ -19,28 +33,27 @@
*/
abstract class DartFixContributor implements FixContributor {
@override
- List<Fix> computeFixes(ResourceProvider resourceProvider,
- AnalysisContext context, AnalysisError error) {
- Source source = error.source;
+ Future<List<Fix>> computeFixes(FixContext context) async {
+ AnalysisContext analysisContext = context.analysisContext;
+ Source source = context.error.source;
if (!AnalysisEngine.isDartFileName(source.fullName)) {
return Fix.EMPTY_LIST;
}
- List<Source> libraries = context.getLibrariesContaining(source);
+ List<Source> libraries = analysisContext.getLibrariesContaining(source);
if (libraries.isEmpty) {
return Fix.EMPTY_LIST;
}
CompilationUnit unit =
- context.resolveCompilationUnit2(source, libraries[0]);
+ analysisContext.resolveCompilationUnit2(source, libraries[0]);
if (unit == null) {
return Fix.EMPTY_LIST;
}
- return internalComputeFixes(resourceProvider, unit, error);
+ DartFixContext dartContext = new DartFixContextImpl(context, unit);
+ return internalComputeFixes(dartContext);
}
/**
- * Return a list of fixes for the given [error]. The error was reported
- * against the given compilation [unit].
+ * Return a list of fixes for the given [context].
*/
- List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
- CompilationUnit unit, AnalysisError error);
+ Future<List<Fix>> internalComputeFixes(DartFixContext context);
}
diff --git a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 26a0080..81ad8dc 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -938,6 +938,176 @@
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
*
@@ -9277,6 +9447,7 @@
* "explicitFileCount": int
* "implicitFileCount": int
* "workItemQueueLength": int
+ * "workItemQueueLengthAverage": String
* "cacheEntryExceptions": List<String>
* }
*
@@ -9291,6 +9462,8 @@
int _workItemQueueLength;
+ String _workItemQueueLengthAverage;
+
List<String> _cacheEntryExceptions;
/**
@@ -9346,6 +9519,21 @@
}
/**
+ * A rolling average of work items in the queue. (A double encoded as a
+ * String.)
+ */
+ String get workItemQueueLengthAverage => _workItemQueueLengthAverage;
+
+ /**
+ * A rolling average of work items in the queue. (A double encoded as a
+ * String.)
+ */
+ void set workItemQueueLengthAverage(String value) {
+ assert(value != null);
+ this._workItemQueueLengthAverage = value;
+ }
+
+ /**
* Exceptions associated with cache entries.
*/
List<String> get cacheEntryExceptions => _cacheEntryExceptions;
@@ -9358,11 +9546,12 @@
this._cacheEntryExceptions = value;
}
- ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, List<String> cacheEntryExceptions) {
+ ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, String workItemQueueLengthAverage, List<String> cacheEntryExceptions) {
this.name = name;
this.explicitFileCount = explicitFileCount;
this.implicitFileCount = implicitFileCount;
this.workItemQueueLength = workItemQueueLength;
+ this.workItemQueueLengthAverage = workItemQueueLengthAverage;
this.cacheEntryExceptions = cacheEntryExceptions;
}
@@ -9395,13 +9584,19 @@
} else {
throw jsonDecoder.missingKey(jsonPath, "workItemQueueLength");
}
+ String workItemQueueLengthAverage;
+ if (json.containsKey("workItemQueueLengthAverage")) {
+ workItemQueueLengthAverage = jsonDecoder.decodeString(jsonPath + ".workItemQueueLengthAverage", json["workItemQueueLengthAverage"]);
+ } else {
+ throw jsonDecoder.missingKey(jsonPath, "workItemQueueLengthAverage");
+ }
List<String> cacheEntryExceptions;
if (json.containsKey("cacheEntryExceptions")) {
cacheEntryExceptions = jsonDecoder.decodeList(jsonPath + ".cacheEntryExceptions", json["cacheEntryExceptions"], jsonDecoder.decodeString);
} else {
throw jsonDecoder.missingKey(jsonPath, "cacheEntryExceptions");
}
- return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, cacheEntryExceptions);
+ return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, workItemQueueLengthAverage, cacheEntryExceptions);
} else {
throw jsonDecoder.mismatch(jsonPath, "ContextData", json);
}
@@ -9413,6 +9608,7 @@
result["explicitFileCount"] = explicitFileCount;
result["implicitFileCount"] = implicitFileCount;
result["workItemQueueLength"] = workItemQueueLength;
+ result["workItemQueueLengthAverage"] = workItemQueueLengthAverage;
result["cacheEntryExceptions"] = cacheEntryExceptions;
return result;
}
@@ -9427,6 +9623,7 @@
explicitFileCount == other.explicitFileCount &&
implicitFileCount == other.implicitFileCount &&
workItemQueueLength == other.workItemQueueLength &&
+ workItemQueueLengthAverage == other.workItemQueueLengthAverage &&
listEqual(cacheEntryExceptions, other.cacheEntryExceptions, (String a, String b) => a == b);
}
return false;
@@ -9439,6 +9636,7 @@
hash = JenkinsSmiHash.combine(hash, explicitFileCount.hashCode);
hash = JenkinsSmiHash.combine(hash, implicitFileCount.hashCode);
hash = JenkinsSmiHash.combine(hash, workItemQueueLength.hashCode);
+ hash = JenkinsSmiHash.combine(hash, workItemQueueLengthAverage.hashCode);
hash = JenkinsSmiHash.combine(hash, cacheEntryExceptions.hashCode);
return JenkinsSmiHash.finish(hash);
}
@@ -13892,6 +14090,7 @@
* 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
@@ -13950,6 +14149,12 @@
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.
*/
@@ -14055,7 +14260,7 @@
/**
* 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;
@@ -14075,6 +14280,8 @@
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":
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol.dart b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
index 823ffd6..5617efc 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
@@ -20,7 +20,7 @@
*
* Clients may not extend, implement or mix-in this class.
*/
-abstract class DomainHandler extends RequestHandler {
+abstract class DomainHandler implements RequestHandler {
/**
* Perform any operations associated with the shutdown of the domain. It is
* not guaranteed that this method will be called. If it is, it will be
@@ -411,6 +411,16 @@
'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
* not in the current list of analysis roots.
diff --git a/pkg/analysis_server/lib/src/analysis_logger.dart b/pkg/analysis_server/lib/src/analysis_logger.dart
index 04ad6c6..bc2276e 100644
--- a/pkg/analysis_server/lib/src/analysis_logger.dart
+++ b/pkg/analysis_server/lib/src/analysis_logger.dart
@@ -43,8 +43,7 @@
} else {
baseLogger.severe(message, exception.exception, exception.stackTrace);
}
- server.sendServerErrorNotification(
- message, exception, exception?.stackTrace);
+ server.sendServerErrorNotification(message, exception, null);
}
@override
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 93c929c..6a5ace1 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -892,35 +892,28 @@
/**
* Sends a `server.error` notification.
*/
- void sendServerErrorNotification(String msg, exception, stackTrace,
+ void sendServerErrorNotification(String message, exception, stackTrace,
{bool fatal: false}) {
- // prepare exception.toString()
- String exceptionString;
+ StringBuffer buffer = new StringBuffer();
if (exception != null) {
- exceptionString = exception.toString();
+ buffer.write(exception);
} else {
- exceptionString = 'null exception';
+ buffer.write('null exception');
}
- // prepare message
- String message = msg != null ? '$msg\n$exceptionString' : exceptionString;
- // prepare stackTrace.toString()
- String stackTraceString;
if (stackTrace != null) {
- stackTraceString = stackTrace.toString();
- } else {
+ buffer.writeln();
+ buffer.write(stackTrace);
+ } else if (exception is! CaughtException) {
try {
throw 'ignored';
} catch (ignored, stackTrace) {
- stackTraceString = stackTrace.toString();
- }
- if (stackTraceString == null) {
- // This code should be unreachable.
- stackTraceString = 'null stackTrace';
+ buffer.writeln();
+ buffer.write(stackTrace);
}
}
// send the notification
channel.sendNotification(
- new ServerErrorParams(fatal, message, stackTraceString)
+ new ServerErrorParams(fatal, message, buffer.toString())
.toNotification());
}
@@ -977,8 +970,11 @@
Set<String> todoFiles =
oldFiles != null ? newFiles.difference(oldFiles) : newFiles;
for (String file in todoFiles) {
- ContextSourcePair contextSource = getContextSourcePair(file);
+ if (contextManager.isIgnored(file)) {
+ continue;
+ }
// prepare context
+ ContextSourcePair contextSource = getContextSourcePair(file);
AnalysisContext context = contextSource.context;
if (context == null) {
continue;
@@ -1066,6 +1062,11 @@
List<String> unanalyzed = new List<String>();
Source firstSource = null;
files.forEach((String file) {
+ if (contextManager.isIgnored(file)) {
+ unanalyzed.add(file);
+ return;
+ }
+ // Prepare the context/source pair.
ContextSourcePair contextSource = getContextSourcePair(file);
AnalysisContext preferredContext = contextSource.context;
Source source = contextSource.source;
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index a32ad98..0d90251 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -26,6 +26,7 @@
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 =
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index e45846d..061cc23 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -181,6 +181,31 @@
void setDependencies(Iterable<String> newDependencies) {
_dependencies = newDependencies.toSet();
}
+
+ /**
+ * Return `true` if the given [path] is managed by this context or by
+ * any of its children.
+ */
+ bool _managesOrHasChildThatManages(String path) {
+ if (parent == null) {
+ for (ContextInfo child in children) {
+ if (child._managesOrHasChildThatManages(path)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ if (!folder.isOrContains(path)) {
+ return false;
+ }
+ for (ContextInfo child in children) {
+ if (child._managesOrHasChildThatManages(path)) {
+ return true;
+ }
+ }
+ return !pathFilter.ignored(path);
+ }
+ }
}
/**
@@ -241,6 +266,12 @@
AnalysisContext getContextFor(String path);
/**
+ * Return `true` if the given [path] is ignored by a [ContextInfo] whose
+ * folder contains it.
+ */
+ bool isIgnored(String path);
+
+ /**
* Return `true` if the given absolute [path] is in one of the current
* root folders and is not excluded.
*/
@@ -419,7 +450,7 @@
* Virtual [ContextInfo] which acts as the ancestor of all other
* [ContextInfo]s.
*/
- final ContextInfo _rootInfo = new ContextInfo._root();
+ final ContextInfo rootInfo = new ContextInfo._root();
/**
* Stream subscription we are using to watch each analysis root directory for
@@ -474,13 +505,27 @@
}
@override
+ bool isIgnored(String path) {
+ ContextInfo info = rootInfo;
+ do {
+ info = info.findChildInfoFor(path);
+ if (info == null) {
+ return false;
+ }
+ if (info.ignored(path)) {
+ return true;
+ }
+ } while (true);
+ }
+
+ @override
bool isInAnalysisRoot(String path) {
// check if excluded
if (_isExcluded(path)) {
return false;
}
// check if in one of the roots
- for (ContextInfo info in _rootInfo.children) {
+ for (ContextInfo info in rootInfo.children) {
if (info.folder.contains(path)) {
return true;
}
@@ -555,7 +600,7 @@
@override
void refresh(List<Resource> roots) {
// Destroy old contexts
- List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
+ List<ContextInfo> contextInfos = rootInfo.descendants.toList();
if (roots == null) {
contextInfos.forEach(_destroyContext);
} else {
@@ -596,22 +641,31 @@
}
});
- List<ContextInfo> contextInfos = _rootInfo.descendants.toList();
+ List<ContextInfo> contextInfos = rootInfo.descendants.toList();
// included
- Set<Folder> includedFolders = new HashSet<Folder>();
- for (int i = 0; i < includedPaths.length; i++) {
- String path = includedPaths[i];
- Resource resource = resourceProvider.getResource(path);
- if (resource is Folder) {
- includedFolders.add(resource);
- } else if (!resource.exists) {
- // Non-existent resources are ignored. TODO(paulberry): we should set
- // up a watcher to ensure that if the resource appears later, we will
- // begin analyzing it.
- } else {
- // TODO(scheglov) implemented separate files analysis
- throw new UnimplementedError('$path is not a folder. '
- 'Only support for folder analysis is implemented currently.');
+ List<Folder> includedFolders = <Folder>[];
+ {
+ // Sort paths to ensure that outer roots are handled before inner roots,
+ // so we can correctly ignore inner roots, which are already managed
+ // by outer roots.
+ LinkedHashSet<String> uniqueIncludedPaths =
+ new LinkedHashSet<String>.from(includedPaths);
+ List<String> sortedIncludedPaths = uniqueIncludedPaths.toList();
+ sortedIncludedPaths.sort((a, b) => a.length - b.length);
+ // Convert paths to folders.
+ for (String path in sortedIncludedPaths) {
+ Resource resource = resourceProvider.getResource(path);
+ if (resource is Folder) {
+ includedFolders.add(resource);
+ } else if (!resource.exists) {
+ // Non-existent resources are ignored. TODO(paulberry): we should set
+ // up a watcher to ensure that if the resource appears later, we will
+ // begin analyzing it.
+ } else {
+ // TODO(scheglov) implemented separate files analysis
+ throw new UnimplementedError('$path is not a folder. '
+ 'Only support for folder analysis is implemented currently.');
+ }
}
}
this.includedPaths = includedPaths;
@@ -628,7 +682,7 @@
}
}
// Update package roots for existing contexts
- for (ContextInfo info in _rootInfo.descendants) {
+ for (ContextInfo info in rootInfo.descendants) {
String newPackageRoot = normalizedPackageRoots[info.folder.path];
if (info.packageRoot != newPackageRoot) {
info.packageRoot = newPackageRoot;
@@ -637,17 +691,17 @@
}
// create new contexts
for (Folder includedFolder in includedFolders) {
- bool wasIncluded = contextInfos.any((info) {
- return info.folder.isOrContains(includedFolder.path);
- });
- if (!wasIncluded) {
+ String includedPath = includedFolder.path;
+ bool isManaged = rootInfo._managesOrHasChildThatManages(includedPath);
+ if (!isManaged) {
+ ContextInfo parent = _getParentForNewContext(includedPath);
changeSubscriptions[includedFolder] =
includedFolder.changes.listen(_handleWatchEvent);
- _createContexts(_rootInfo, includedFolder, false);
+ _createContexts(parent, includedFolder, false);
}
}
// remove newly excluded sources
- for (ContextInfo info in _rootInfo.descendants) {
+ for (ContextInfo info in rootInfo.descendants) {
// prepare excluded sources
Map<String, Source> excludedSources = new HashMap<String, Source>();
info.sources.forEach((String path, Source source) {
@@ -665,7 +719,7 @@
callbacks.applyChangesToContext(info.folder, changeSet);
}
// add previously excluded sources
- for (ContextInfo info in _rootInfo.descendants) {
+ for (ContextInfo info in rootInfo.descendants) {
ChangeSet changeSet = new ChangeSet();
_addPreviouslyExcludedSources(
info, changeSet, info.folder, oldExcludedPaths);
@@ -802,7 +856,7 @@
for (Source source in context.sources) {
flushedFiles.add(source.fullName);
}
- for (ContextInfo contextInfo in _rootInfo.descendants) {
+ for (ContextInfo contextInfo in rootInfo.descendants) {
AnalysisContext contextN = contextInfo.context;
if (context != contextN) {
for (Source source in contextN.sources) {
@@ -1062,7 +1116,7 @@
* If no context contains the given path, `null` is returned.
*/
ContextInfo _getInnermostContextInfoFor(String path) {
- ContextInfo info = _rootInfo.findChildInfoFor(path);
+ ContextInfo info = rootInfo.findChildInfoFor(path);
if (info == null) {
return null;
}
@@ -1075,6 +1129,17 @@
}
}
+ /**
+ * Return the parent for a new [ContextInfo] with the given [path] folder.
+ */
+ ContextInfo _getParentForNewContext(String path) {
+ ContextInfo parent = _getInnermostContextInfoFor(path);
+ if (parent != null) {
+ return parent;
+ }
+ return rootInfo;
+ }
+
void _handleWatchEvent(WatchEvent event) {
// Figure out which context this event applies to.
// TODO(brianwilkerson) If a file is explicitly included in one context
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index 494d37c..f1bdf14 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -21,6 +21,7 @@
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 @@
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 @@
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) {
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 6d43e53..370e7bf 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -12,6 +12,7 @@
import 'package:analysis_server/src/context_manager.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart'
show CompletionRequest, CompletionResult;
+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/search/search_engine.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -100,7 +101,7 @@
}
_discardManager();
}
- _manager = createCompletionManager(context, source, searchEngine);
+ _manager = createCompletionManager(server, context, source);
if (context != null) {
_sourcesChangedSubscription =
context.onSourcesChanged.listen(sourcesChanged);
@@ -122,8 +123,9 @@
}
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
@@ -194,8 +196,8 @@
if (manager == null) {
manager = completionManagerFor(context, source);
}
- CompletionRequest completionRequest =
- new CompletionRequestImpl(server, context, source, params.offset);
+ CompletionRequest completionRequest = new CompletionRequestImpl(context,
+ server.resourceProvider, server.searchEngine, source, params.offset);
int notificationCount = 0;
manager.results(completionRequest).listen((CompletionResult result) {
++notificationCount;
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index e6c08c4..5d30d92 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -4,11 +4,13 @@
library src.domain_diagnostic;
+import 'dart:async';
import 'dart:collection';
import 'dart:core' hide Resource;
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/utilities/average.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
@@ -19,42 +21,10 @@
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/task/model.dart';
-/// Extract context data from the given [context].
-ContextData extractData(AnalysisContext context) {
- int explicitFiles = 0;
- int implicitFiles = 0;
- int workItems = 0;
- Set<String> exceptions = new HashSet<String>();
- if (context is AnalysisContextImpl) {
- // Work Item count.
- AnalysisDriver driver = context.driver;
- List<WorkItem> items = driver.currentWorkOrder?.workItems;
- workItems ??= items?.length;
- var cache = context.analysisCache;
- if (cache is AnalysisCache) {
- Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
- MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
- while (iterator.moveNext()) {
- AnalysisTarget target = iterator.key;
- if (countedTargets.add(target)) {
- CacheEntry cacheEntry = iterator.value;
- if (target is Source) {
- if (cacheEntry.explicitlyAdded) {
- explicitFiles++;
- } else {
- implicitFiles++;
- }
- }
- // Caught exceptions.
- if (cacheEntry.exception != null) {
- exceptions.add(cacheEntry.exception.toString());
- }
- }
- }
- }
- }
- return new ContextData(context.name, explicitFiles, implicitFiles, workItems,
- exceptions.toList());
+int _workItemCount(AnalysisContextImpl context) {
+ AnalysisDriver driver = context.driver;
+ List<WorkItem> items = driver.currentWorkOrder?.workItems;
+ return items?.length ?? 0;
}
/// Instances of the class [DiagnosticDomainHandler] implement a
@@ -66,20 +36,65 @@
/// The analysis server that is using this handler to process requests.
final AnalysisServer server;
+ /// The sampler tracking rolling work queue length averages.
+ Sampler sampler;
+
/// Initialize a newly created handler to handle requests for the given
/// [server].
DiagnosticDomainHandler(this.server);
/// Answer the `diagnostic.diagnostics` request.
Response computeDiagnostics(Request request) {
+ // Initialize sampler if needed.
+ if (sampler == null) {
+ sampler = new Sampler(server);
+ }
+
List<ContextData> infos = <ContextData>[];
server.folderMap.forEach((Folder folder, AnalysisContext context) {
- infos.add(extractData(context));
+ infos.add(extractData(folder, context));
});
return new DiagnosticGetDiagnosticsResult(infos).toResponse(request.id);
}
+ /// Extract context data from the given [context].
+ ContextData extractData(Folder folder, AnalysisContext context) {
+ int explicitFiles = 0;
+ int implicitFiles = 0;
+ int workItems = 0;
+ String workItemAverage = '-1';
+ Set<String> exceptions = new HashSet<String>();
+ if (context is AnalysisContextImpl) {
+ workItems = _workItemCount(context);
+ workItemAverage = sampler.getAverage(folder)?.toString() ?? '-1';
+ var cache = context.analysisCache;
+ if (cache is AnalysisCache) {
+ Set<AnalysisTarget> countedTargets = new HashSet<AnalysisTarget>();
+ MapIterator<AnalysisTarget, CacheEntry> iterator = cache.iterator();
+ while (iterator.moveNext()) {
+ AnalysisTarget target = iterator.key;
+ if (countedTargets.add(target)) {
+ CacheEntry cacheEntry = iterator.value;
+ if (target is Source) {
+ if (cacheEntry.explicitlyAdded) {
+ explicitFiles++;
+ } else {
+ implicitFiles++;
+ }
+ }
+ // Caught exceptions.
+ if (cacheEntry.exception != null) {
+ exceptions.add(cacheEntry.exception.toString());
+ }
+ }
+ }
+ }
+ }
+ return new ContextData(context.name, explicitFiles, implicitFiles,
+ workItems, workItemAverage, exceptions.toList());
+ }
+
@override
Response handleRequest(Request request) {
try {
@@ -93,3 +108,83 @@
return null;
}
}
+
+/// Keeps track of a moving average of work item queue lengths mapped to
+/// contexts.
+///
+/// Sampling terminates after [maxSampleCount], if no one expresses interest
+/// by calling [resetTimerCountdown].
+class Sampler {
+ /// Timer interval.
+ static const Duration duration = const Duration(seconds: 1);
+
+ /// Maximum number of samples taken between calls to [reset].
+ static const int maxSampleCount = 30;
+
+ /// Current sample count.
+ int sampleCount = 0;
+
+ /// The shared timer.
+ Timer timer;
+
+ /// Map of contexts (tracked as folders to avoid leaks) to averages.
+ /// TOOD(pq): consider adding GC to remove mappings for deleted folders
+ Map<Folder, Average> averages = new HashMap<Folder, Average>();
+
+ final AnalysisServer server;
+ Sampler(this.server) {
+ start();
+ _sample();
+ }
+
+ /// Get the average for the context associated with the given [folder].
+ num getAverage(Folder folder) {
+ resetTimerCountdown();
+ return averages[folder].value;
+ }
+
+ /// Check if we're currently sampling.
+ bool isSampling() => timer?.isActive ?? false;
+
+ /// Reset counter.
+ void resetTimerCountdown() {
+ sampleCount = 0;
+ }
+
+ /// Start sampling.
+ void start() {
+ // No need to (re)start if already sampling.
+ if (isSampling()) {
+ return;
+ }
+ timer = new Timer.periodic(duration, (Timer timer) {
+ _sample();
+ if (sampleCount++ >= maxSampleCount) {
+ timer.cancel();
+ }
+ });
+ }
+
+ /// Stop sampling.
+ void stop() {
+ timer.cancel();
+ }
+
+ /// Take a sample.
+ void _sample() {
+ try {
+ server.folderMap.forEach((Folder folder, AnalysisContext context) {
+ if (context is AnalysisContextImpl) {
+ Average average = averages[folder];
+ if (average == null) {
+ average = new Average();
+ averages[folder] = average;
+ }
+ average.addSample(_workItemCount(context));
+ }
+ });
+ } on Exception {
+ stop();
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index f96f42f..2321ee3 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -54,23 +54,38 @@
}
void _addMemberIfImplemented(Element element) {
- if (!element.isSynthetic) {
- String name = element.displayName;
- if (name != null && _hasOverride(name)) {
- _addImplementedMember(element);
- }
+ if (element.isSynthetic || _isStatic(element)) {
+ return;
+ }
+ String name = element.displayName;
+ if (name != null && _hasOverride(name)) {
+ _addImplementedMember(element);
}
}
bool _hasOverride(String name) {
for (ClassElement subtype in subtypes) {
- if (subtype.getMethod(name) != null) {
- return true;
+ MethodElement method = subtype.getMethod(name);
+ if (method != null) {
+ return !method.isStatic;
}
- if (subtype.getField(name) != null) {
- return true;
+ FieldElement field = subtype.getField(name);
+ if (field != null) {
+ return !field.isStatic;
}
}
return false;
}
+
+ /**
+ * Return `true` if the given [element] is a static element.
+ */
+ static bool _isStatic(Element element) {
+ if (element is ExecutableElement) {
+ return element.isStatic;
+ } else if (element is PropertyInducingElement) {
+ return element.isStatic;
+ }
+ return false;
+ }
}
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index dc4616f..20ed6aa 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -243,6 +243,19 @@
}
@override
+ visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
+ Element element = node.staticElement;
+ if (element != null && element.isSynthetic) {
+ element = element.enclosingElement;
+ }
+ // add region
+ computer._addRegionForToken(node.thisKeyword, element);
+ computer._addRegionForNode(node.constructorName, element);
+ // process arguments
+ _safelyVisit(node.argumentList);
+ }
+
+ @override
visitSimpleIdentifier(SimpleIdentifier node) {
if (node.parent is ConstructorDeclaration) {
return;
@@ -258,12 +271,8 @@
element = element.enclosingElement;
}
// add region
- SimpleIdentifier name = node.constructorName;
- if (name != null) {
- computer._addRegion_nodeStart_nodeEnd(node, name, element);
- } else {
- computer._addRegionForToken(node.superKeyword, element);
- }
+ computer._addRegionForToken(node.superKeyword, element);
+ computer._addRegionForNode(node.constructorName, element);
// process arguments
_safelyVisit(node.argumentList);
}
@@ -279,7 +288,16 @@
}
// add regions
TypeName typeName = node.type;
- computer._addRegionForNode(typeName.name, element);
+ // [prefix].ClassName
+ {
+ Identifier name = typeName.name;
+ Identifier className = name;
+ if (name is PrefixedIdentifier) {
+ name.prefix.accept(this);
+ className = name.identifier;
+ }
+ computer._addRegionForNode(className, element);
+ }
// <TypeA, TypeB>
TypeArgumentList typeArguments = typeName.typeArguments;
if (typeArguments != null) {
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index e14f3b3..1865146 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -130,23 +130,25 @@
.toResponse(request.id);
}
- Response getAssists(Request request) {
+ Future getAssists(Request request) async {
EditGetAssistsParams params = new EditGetAssistsParams.fromRequest(request);
ContextSourcePair pair = server.getContextSourcePair(params.file);
engine.AnalysisContext context = pair.context;
Source source = pair.source;
List<SourceChange> changes = <SourceChange>[];
if (context != null && source != null) {
- List<Assist> assists = computeAssists(
+ List<Assist> assists = await computeAssists(
server.serverPlugin, context, source, params.offset, params.length);
assists.forEach((Assist assist) {
changes.add(assist.change);
});
}
- return new EditGetAssistsResult(changes).toResponse(request.id);
+ Response response =
+ new EditGetAssistsResult(changes).toResponse(request.id);
+ server.sendResponse(response);
}
- Response getFixes(Request request) {
+ getFixes(Request request) async {
var params = new EditGetFixesParams.fromRequest(request);
String file = params.file;
int offset = params.offset;
@@ -161,7 +163,7 @@
for (engine.AnalysisError error in errorInfo.errors) {
int errorLine = lineInfo.getLocation(error.offset).lineNumber;
if (errorLine == requestLine) {
- List<Fix> fixes = computeFixes(server.serverPlugin,
+ List<Fix> fixes = await computeFixes(server.serverPlugin,
server.resourceProvider, unit.element.context, error);
if (fixes.isNotEmpty) {
AnalysisError serverError =
@@ -178,7 +180,8 @@
}
}
// respond
- return new EditGetFixesResult(errorFixesList).toResponse(request.id);
+ return server.sendResponse(
+ new EditGetFixesResult(errorFixesList).toResponse(request.id));
}
@override
@@ -188,11 +191,13 @@
if (requestName == EDIT_FORMAT) {
return format(request);
} else if (requestName == EDIT_GET_ASSISTS) {
- return getAssists(request);
+ getAssists(request);
+ return Response.DELAYED_RESPONSE;
} else if (requestName == EDIT_GET_AVAILABLE_REFACTORINGS) {
return _getAvailableRefactorings(request);
} else if (requestName == EDIT_GET_FIXES) {
- return getFixes(request);
+ getFixes(request);
+ return Response.DELAYED_RESPONSE;
} else if (requestName == EDIT_GET_REFACTORING) {
return _getRefactoring(request);
} else if (requestName == EDIT_ORGANIZE_DIRECTIVES) {
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index a7a13dd..b35d5bd 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -14,8 +14,6 @@
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analysis_server/plugin/edit/fix/fix.dart';
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
-import 'package:analysis_server/plugin/index/index.dart';
-import 'package:analysis_server/plugin/index/index_core.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/domain_analysis.dart';
@@ -27,6 +25,8 @@
import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
import 'package:analysis_server/src/edit/edit_domain.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/index/index.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/search/search_domain.dart';
import 'package:analysis_server/src/services/correction/assist_internal.dart';
import 'package:analysis_server/src/services/correction/fix_internal.dart';
@@ -189,8 +189,9 @@
* 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.
@@ -291,7 +292,7 @@
// Register completion contributors.
//
// TODO(brianwilkerson) Register the completion contributors.
-// registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
+ //registerExtension(COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID, ???);
//
// Register analysis contributors.
//
@@ -370,10 +371,10 @@
* 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');
}
}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
index 9a71bc0..68eb362 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
@@ -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,
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index af69cd0..bdebfcc 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
@@ -4,51 +4,39 @@
library analysis_server.src.provisional.completion.completion_core;
+import 'dart:async';
+
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/task/model.dart';
/**
- * A method or function called when the requested analysis has been performed.
+ * An empty list returned by [CompletionContributor]s
+ * when they have no suggestions to contribute.
*/
-typedef AnalysisRequest AnalysisCallback<V>(
- CompletionRequest request, V computedValue);
+const EMPTY_LIST = const <CompletionSuggestion>[];
/**
- * A request from a contributor for additional analysis.
+ * An object used to instantiate a [CompletionContributor] instance
+ * for each 'completion.getSuggestions' request.
+ * Contributors should *not* be cached between requests.
*/
-class AnalysisRequest<V> {
- /**
- * An object with which an analysis result can be associated.
- */
- AnalysisTarget target;
-
- /**
- * A description of an analysis result that can be computed by an [AnalysisTask].
- */
- ResultDescriptor<V> descriptor;
-
- /**
- * A method or function called when the requested analysis has been performed.
- */
- AnalysisCallback<V> callback;
-
- AnalysisRequest(this.target, this.descriptor, this.callback);
-}
+typedef CompletionContributor CompletionContributorFactory();
/**
* An object used to produce completions at a specific location within a file.
*
- * Clients may extend this class when implementing plugins.
+ * Clients may implement this class when implementing plugins.
*/
abstract class CompletionContributor {
/**
- * Compute a list of completion suggestions based on the given completion
- * [request]. Return the suggestions that were computed.
+ * Return a [Future] that completes with a list of suggestions
+ * for the given completion [request].
*/
- List<CompletionSuggestion> computeSuggestions(CompletionRequest request);
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ CompletionRequest request);
}
/**
@@ -74,6 +62,11 @@
ResourceProvider get resourceProvider;
/**
+ * Return the search engine.
+ */
+ SearchEngine get searchEngine;
+
+ /**
* Return the source in which the completion is being requested.
*/
Source get source;
diff --git a/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
deleted file mode 100644
index e52c433..0000000
--- a/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
+++ /dev/null
@@ -1,90 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analysis_server.src.provisional.completion.completion_dart;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-/**
- * An object used to produce completions for a specific error within a Dart
- * file. Completion contributors are long-lived objects and must not retain any
- * state between invocations of [computeSuggestions].
- *
- * Clients may extend this class when implementing plugins.
- */
-abstract class DartCompletionContributor implements CompletionContributor {
- @override
- List<CompletionSuggestion> computeSuggestions(CompletionRequest request) {
- if (request is DartCompletionRequest) {
- return internalComputeSuggestions(request);
- }
- AnalysisContext context = request.context;
- Source source = request.source;
- List<Source> libraries = context.getLibrariesContaining(source);
- if (libraries.length < 1) {
- return null;
- }
-// CompilationUnit unit =
-// context.getResolvedCompilationUnit2(source, libraries[0]);
-// bool isResolved = true;
-// if (unit == null) {
-// // TODO(brianwilkerson) Implement a method for getting a parsed
-// // compilation unit without parsing the unit if it hasn't been parsed.
-// unit = context.getParsedCompilationUnit(source);
-// if (unit == null) {
-// return null;
-// }
-// isResolved = false;
-// }
-// DartCompletionRequest dartRequest =
-// new DartCompletionRequestImpl(request, unit, isResolved);
-// return internalComputeSuggestions(dartRequest);
- return null;
- }
-
- /**
- * Compute a list of completion suggestions based on the given completion
- * [request]. Return the suggestions that were computed.
- */
- List<CompletionSuggestion> internalComputeSuggestions(
- DartCompletionRequest request);
-}
-
-/**
- * The information about a requested list of completions within a Dart file.
- *
- * Clients may not extend, implement or mix-in this class.
- */
-abstract class DartCompletionRequest extends CompletionRequest {
- /**
- * Return `true` if the compilation [unit] is resolved.
- */
- bool get isResolved;
-
- /**
- * Return the completion target. This determines what part of the parse tree
- * will receive the newly inserted text.
- */
- CompletionTarget get target;
-
- /**
- * Cached information from a prior code completion operation.
- */
- //DartCompletionCache get cache;
-
- /**
- * Return the compilation unit in which the completion was requested.
- */
- CompilationUnit get unit;
-
- /**
- * Information about the types of suggestions that should be included.
- */
- //OpType get _optype;
-}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart
new file mode 100644
index 0000000..4d6601d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion.dart
@@ -0,0 +1,40 @@
+// 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.
+
+/**
+ * Support for client code that extends the analysis server by adding new
+ * Dart specific completion contributors.
+ *
+ * Plugins can register Dart specific 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
+ * [DartCompletionContributorFactory] by including code
+ * like the following in the plugin's registerExtensions method:
+ *
+ * @override
+ * void registerExtensions(RegisterExtension registerExtension) {
+ * ...
+ * registerExtension(
+ * DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ * () => new MyDartCompletionContributor());
+ * ...
+ * }
+ */
+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';
+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
+ * [DartCompletionContributorFactory].
+ */
+final String DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
+ DartCompletionPlugin.UNIQUE_IDENTIFIER,
+ DartCompletionPlugin.CONTRIBUTOR_EXTENSION_POINT);
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
new file mode 100644
index 0000000..816894d
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -0,0 +1,86 @@
+// 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 analysis_server.src.provisional.completion.completion_dart;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analyzer/src/generated/ast.dart';
+
+export 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show EMPTY_LIST;
+
+const int DART_RELEVANCE_COMMON_USAGE = 1200;
+const int DART_RELEVANCE_DEFAULT = 1000;
+const int DART_RELEVANCE_HIGH = 2000;
+const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
+const int DART_RELEVANCE_INHERITED_FIELD = 1058;
+const int DART_RELEVANCE_INHERITED_METHOD = 1057;
+const int DART_RELEVANCE_KEYWORD = 1055;
+const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
+const int DART_RELEVANCE_LOCAL_FIELD = 1058;
+const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
+const int DART_RELEVANCE_LOCAL_METHOD = 1057;
+const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
+const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
+const int DART_RELEVANCE_LOW = 500;
+const int DART_RELEVANCE_NAMED_PARAMETER = 1060;
+const int DART_RELEVANCE_PARAMETER = 1059;
+
+/**
+ * An object used to instantiate a [DartCompletionContributor] instance
+ * for each 'completion.getSuggestions' request.
+ * Contributors should *not* be cached between requests.
+ */
+typedef DartCompletionContributor DartCompletionContributorFactory();
+
+/**
+ * An object used to produce completions
+ * at a specific location within a Dart file.
+ *
+ * Clients may implement this class when implementing plugins.
+ */
+abstract class DartCompletionContributor {
+ /**
+ * Return a [Future] that completes with a list of suggestions
+ * for the given completion [request].
+ */
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request);
+}
+
+/**
+ * The information about a requested list of completions within a Dart file.
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+abstract class DartCompletionRequest extends CompletionRequest {
+ /**
+ * Return the completion target. This determines what part of the parse tree
+ * will receive the newly inserted text.
+ */
+ CompletionTarget get target;
+
+ /**
+ * Return a [Future] that completes with a compilation unit in which
+ * all declarations in all scopes containing [target] have been resolved.
+ * The [Future] may return `null` if the unit cannot be resolved
+ * (e.g. unlinked part file).
+ * Any information obtained from [target] prior to calling this method
+ * should be discarded as it may have changed.
+ */
+ Future<CompilationUnit> resolveDeclarationsInScope();
+
+ /**
+ * Return a [Future] that completes when the element associated with
+ * the given [identifier] is available or if the identifier cannot be resolved
+ * (e.g. unknown identifier, completion aborted, etc).
+ * Any information obtained from [target] prior to calling this method
+ * should be discarded as it may have changed.
+ */
+ Future resolveIdentifier(SimpleIdentifier identifier);
+}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
new file mode 100644
index 0000000..2b73a30
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -0,0 +1,91 @@
+// 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 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/arglist_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/combinator_contributor.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:analysis_server/src/services/completion/dart/uri_contributor.dart';
+import 'package:plugin/plugin.dart';
+
+/**
+ * The shared dart completion plugin instance.
+ */
+final DartCompletionPlugin dartCompletionPlugin = new DartCompletionPlugin();
+
+class DartCompletionPlugin implements Plugin {
+ /**
+ * The simple identifier of the extension point that allows plugins to
+ * register Dart specific completion contributor factories.
+ * Use [DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID]
+ * when registering contributors.
+ */
+ static const String CONTRIBUTOR_EXTENSION_POINT = 'contributor';
+
+ /**
+ * The unique identifier of this plugin.
+ */
+ static const String UNIQUE_IDENTIFIER = 'dart.completion';
+
+ /**
+ * The extension point that allows plugins to register Dart specific
+ * completion contributor factories.
+ */
+ ExtensionPoint _contributorExtensionPoint;
+
+ @override
+ String get uniqueIdentifier => UNIQUE_IDENTIFIER;
+
+ /**
+ * Return a list containing all of the Dart specific completion contributors.
+ */
+ Iterable<DartCompletionContributorFactory> get contributors =>
+ _contributorExtensionPoint.extensions
+ .map((DartCompletionContributorFactory factory) => factory());
+
+ @override
+ void registerExtensionPoints(RegisterExtensionPoint registerExtensionPoint) {
+ _contributorExtensionPoint = registerExtensionPoint(
+ CONTRIBUTOR_EXTENSION_POINT,
+ _validateDartCompletionContributorExtension);
+ }
+
+ @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 ArgListContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new CombinatorContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new KeywordContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new UriContributor());
+ }
+
+ /**
+ * Validate the given extension by throwing an [ExtensionError] if it is not a
+ * valid Dart specific completion contributor.
+ */
+ void _validateDartCompletionContributorExtension(Object extension) {
+ if (extension is! DartCompletionContributorFactory) {
+ String id = _contributorExtensionPoint.uniqueIdentifier;
+ throw new ExtensionError(
+ 'Extensions to $id must be a DartCompletionContributorFactory');
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index e94016a..0cb0035 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -86,6 +86,11 @@
*/
class CompletionTarget {
/**
+ * The compilation unit in which the completion is occurring.
+ */
+ final CompilationUnit unit;
+
+ /**
* The context in which the completion is occurring. This is the AST node
* which is a direct parent of [entity].
*/
@@ -156,10 +161,12 @@
// Try to replace with a comment token.
Token commentToken = _getContainingCommentToken(entity, offset);
if (commentToken != null) {
- return new CompletionTarget._(containingNode, commentToken, true);
+ return new CompletionTarget._(
+ compilationUnit, containingNode, commentToken, true);
}
// Target found.
- return new CompletionTarget._(containingNode, entity, false);
+ return new CompletionTarget._(
+ compilationUnit, containingNode, entity, false);
} else {
// Since entity is a token, we don't need to look inside it; just
// proceed to the next entity.
@@ -189,10 +196,11 @@
containingNode = docComment;
} else {
return new CompletionTarget._(
- compilationUnit, commentToken, true);
+ compilationUnit, compilationUnit, commentToken, true);
}
}
- return new CompletionTarget._(containingNode, entity, false);
+ return new CompletionTarget._(
+ compilationUnit, containingNode, entity, false);
}
// Otherwise, the completion target is somewhere inside the entity,
@@ -216,7 +224,8 @@
// Since no completion target was found, we set the completion target
// entity to null and use the compilationUnit as the parent.
- return new CompletionTarget._(compilationUnit, null, false);
+ return new CompletionTarget._(
+ compilationUnit, compilationUnit, null, false);
}
}
@@ -224,7 +233,8 @@
* Create a [CompletionTarget] holding the given [containingNode] and
* [entity].
*/
- CompletionTarget._(AstNode containingNode, Object entity, this.isCommentText)
+ CompletionTarget._(
+ this.unit, AstNode containingNode, Object entity, this.isCommentText)
: this.containingNode = containingNode,
this.entity = entity,
this.argIndex = _computeArgIndex(containingNode, entity);
diff --git a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
similarity index 100%
rename from pkg/analysis_server/lib/plugin/edit/utilities/change_builder_core.dart
rename to pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_core.dart
diff --git a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
similarity index 98%
rename from pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart
rename to pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
index 7d0e0c7..1f2c887 100644
--- a/pkg/analysis_server/lib/plugin/edit/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/edit/utilities/change_builder_dart.dart
@@ -4,7 +4,7 @@
library analysis_server.plugin.edit.utilities.change_builder_dart;
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
import 'package:analysis_server/src/utilities/change_builder_dart.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/plugin/index/index.dart b/pkg/analysis_server/lib/src/provisional/index/index.dart
similarity index 95%
rename from pkg/analysis_server/lib/plugin/index/index.dart
rename to pkg/analysis_server/lib/src/provisional/index/index.dart
index b87fce9..c67feb2 100644
--- a/pkg/analysis_server/lib/plugin/index/index.dart
+++ b/pkg/analysis_server/lib/src/provisional/index/index.dart
@@ -30,8 +30,8 @@
*/
library analysis_server.plugin.index.index;
-import 'package:analysis_server/plugin/index/index_core.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:plugin/plugin.dart';
/**
diff --git a/pkg/analysis_server/lib/plugin/index/index_core.dart b/pkg/analysis_server/lib/src/provisional/index/index_core.dart
similarity index 100%
rename from pkg/analysis_server/lib/plugin/index/index_core.dart
rename to pkg/analysis_server/lib/src/provisional/index/index_core.dart
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index c0650e0..306477d 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -6,10 +6,10 @@
import 'dart:async';
-import 'package:analysis_server/plugin/index/index_core.dart';
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/search/element_references.dart';
import 'package:analysis_server/src/search/type_hierarchy.dart';
import 'package:analysis_server/src/services/index/index.dart';
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 1238a1c..27fb203 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -12,6 +12,7 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/plugin/linter_plugin.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
import 'package:analysis_server/src/server/http_server.dart';
import 'package:analysis_server/src/server/stdio_server.dart';
import 'package:analysis_server/src/socket_server.dart';
@@ -409,6 +410,7 @@
plugins.addAll(_userDefinedPlugins);
plugins.add(linterPlugin);
plugins.add(linterServerPlugin);
+ plugins.add(dartCompletionPlugin);
// Defer to the extension manager in AE for plugin registration.
AnalysisEngine.instance.userDefinedPlugins = plugins;
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
deleted file mode 100644
index 4f7780d..0000000
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.contributor.dart.arglist;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol_server.dart'
- hide Element, ElementKind;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-
-void _addNamedParameterSuggestion(
- DartCompletionRequest request, List<String> namedArgs, String name) {
- if (name != null && name.length > 0 && !namedArgs.contains(name)) {
- request.addSuggestion(new CompletionSuggestion(
- CompletionSuggestionKind.NAMED_ARGUMENT,
- DART_RELEVANCE_NAMED_PARAMETER,
- '$name: ',
- name.length + 2,
- 0,
- false,
- false));
- }
-}
-
-/**
- * Determine the number of arguments.
- */
-int _argCount(DartCompletionRequest request) {
- AstNode node = request.target.containingNode;
- if (node is ArgumentList) {
- return node.arguments.length;
- }
- return 0;
-}
-
-/**
- * Determine if the completion target is at the end of the list of arguments.
- */
-bool _isAppendingToArgList(DartCompletionRequest request) {
- AstNode node = request.target.containingNode;
- if (node is ArgumentList) {
- var entity = request.target.entity;
- if (entity == node.rightParenthesis) {
- return true;
- }
- if (node.arguments.length > 0 && node.arguments.last == entity) {
- return entity is SimpleIdentifier;
- }
- }
- return false;
-}
-
-/**
- * Determine if the completion target is an emtpy argument list.
- */
-bool _isEmptyArgList(DartCompletionRequest request) {
- AstNode node = request.target.containingNode;
- return node is ArgumentList &&
- node.leftParenthesis.next == node.rightParenthesis;
-}
-
-/**
- * Return a collection of currently specified named arguments
- */
-Iterable<String> _namedArgs(DartCompletionRequest request) {
- AstNode node = request.target.containingNode;
- List<String> namedArgs = new List<String>();
- if (node is ArgumentList) {
- for (Expression arg in node.arguments) {
- if (arg is NamedExpression) {
- namedArgs.add(arg.name.label.name);
- }
- }
- }
- return namedArgs;
-}
-
-/**
- * A contributor for calculating `completion.getSuggestions` request results
- * when the cursor position is inside the arguments to a method call.
- */
-class ArgListContributor extends DartCompletionContributor {
- _ArgSuggestionBuilder builder;
-
- @override
- bool computeFast(DartCompletionRequest request) {
- builder =
- request.target.containingNode.accept(new _ArgListAstVisitor(request));
- return builder == null;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- if (builder != null) {
- return builder.compute(request.target.containingNode);
- }
- return new Future.value(false);
- }
-}
-
-/**
- * A visitor for determining whether an argument list suggestion is needed
- * and instantiating the builder to create the suggestion.
- */
-class _ArgListAstVisitor extends GeneralizingAstVisitor<_ArgSuggestionBuilder> {
- final DartCompletionRequest request;
-
- _ArgListAstVisitor(this.request);
-
- @override
- _ArgSuggestionBuilder visitArgumentList(ArgumentList node) {
- Token leftParen = node.leftParenthesis;
- if (leftParen != null && request.offset > leftParen.offset) {
- AstNode parent = node.parent;
- if (parent is MethodInvocation) {
- SimpleIdentifier selector = parent.methodName;
- if (selector != null) {
- String name = selector.name;
- if (name != null && name.length > 0) {
- if (parent.operator == null) {
- /*
- * If a local declaration is found, then return null
- * indicating that suggestions were added
- * and no further action is necessary
- */
- if (new _LocalArgSuggestionBuilder(request, request.offset, name)
- .visit(node)) {
- return null;
- }
- } else {
- // determine target
- }
- return new _ArgSuggestionBuilder(request, name);
- }
- }
- }
- String constructorName;
- if (parent is Annotation && parent.name != null) {
- constructorName = parent.name.toSource();
- }
- if (parent is InstanceCreationExpression &&
- parent.constructorName != null) {
- constructorName = parent.constructorName.toSource();
- }
- if (constructorName != null && constructorName.length > 0) {
- if (new _LocalArgSuggestionBuilder(
- request, request.offset, constructorName).visit(node)) {
- return null;
- }
- return new _ArgSuggestionBuilder(request, constructorName);
- }
- }
- return null;
- }
-
- @override
- _ArgSuggestionBuilder visitNode(AstNode node) {
- return null;
- }
-}
-
-/**
- * A [_ArgSuggestionBuilder] determines which method or function is being
- * invoked, then builds the argument list suggestion.
- * This operation is instantiated during `computeFast`
- * and calculates the suggestions during `computeFull`.
- */
-class _ArgSuggestionBuilder {
- final DartCompletionRequest request;
- final String methodName;
-
- _ArgSuggestionBuilder(this.request, this.methodName);
-
- Future<bool> compute(ArgumentList node) {
- AstNode parent = node.parent;
- if (parent is MethodInvocation) {
- SimpleIdentifier methodName = parent.methodName;
- if (methodName != null) {
- Element methodElem = methodName.bestElement;
- if (methodElem is ExecutableElement) {
- _addSuggestions(methodElem.parameters);
- }
- }
- }
- if (parent is InstanceCreationExpression) {
- ConstructorName constructorName = parent.constructorName;
- if (constructorName != null) {
- ConstructorElement element = constructorName.staticElement;
- if (element is ExecutableElement) {
- _addSuggestions(element.parameters);
- }
- }
- }
- return new Future.value(false);
- }
-
- void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
- StringBuffer completion = new StringBuffer('(');
- List<String> paramNames = new List<String>();
- List<String> paramTypes = new List<String>();
- for (ParameterElement param in requiredParam) {
- String name = param.name;
- if (name != null && name.length > 0) {
- if (completion.length > 1) {
- completion.write(', ');
- }
- completion.write(name);
- paramNames.add(name);
- paramTypes.add(_getParamType(param));
- }
- }
- completion.write(')');
- CompletionSuggestion suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.ARGUMENT_LIST,
- DART_RELEVANCE_HIGH,
- completion.toString(),
- completion.length,
- 0,
- false,
- false);
- suggestion.parameterNames = paramNames;
- suggestion.parameterTypes = paramTypes;
- request.addSuggestion(suggestion);
- }
-
- void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
- Iterable<String> namedArgs = _namedArgs(request);
- for (ParameterElement param in parameters) {
- if (param.parameterKind == ParameterKind.NAMED) {
- _addNamedParameterSuggestion(request, namedArgs, param.name);
- }
- }
- }
-
- void _addSuggestions(Iterable<ParameterElement> parameters) {
- if (parameters == null || parameters.length == 0) {
- return;
- }
- Iterable<ParameterElement> requiredParam = parameters.where(
- (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
- int requiredCount = requiredParam.length;
- if (requiredCount > 0 && _isEmptyArgList(request)) {
- _addArgListSuggestion(requiredParam);
- return;
- }
- if (_isAppendingToArgList(request)) {
- if (requiredCount == 0 || requiredCount < _argCount(request)) {
- _addDefaultParamSuggestions(parameters);
- }
- }
- }
-
- String _getParamType(ParameterElement param) {
- DartType type = param.type;
- if (type != null) {
- return type.displayName;
- }
- return 'dynamic';
- }
-}
-
-/**
- * [_LocalArgSuggestionBuilder] visits an [AstNode] and its parent recursively
- * looking for a matching declaration. If found, it adds the appropriate
- * suggestions and sets finished to `true`.
- */
-class _LocalArgSuggestionBuilder extends LocalDeclarationVisitor {
- final DartCompletionRequest request;
- final String name;
-
- _LocalArgSuggestionBuilder(this.request, int offset, this.name)
- : super(offset);
-
- @override
- void declaredClass(ClassDeclaration declaration) {
- String className = null;
- if (declaration.name != null) {
- className = declaration.name.name;
- }
- if (className != null && className.length > 0) {
- for (ClassMember member in declaration.members) {
- if (member is ConstructorDeclaration) {
- String selector = className;
- if (member.name != null) {
- selector = '$selector.${member.name.name}';
- }
- if (selector == name) {
- _addSuggestions(member.parameters);
- finished();
- }
- }
- }
- }
- }
-
- @override
- void declaredClassTypeAlias(ClassTypeAlias declaration) {}
-
- @override
- void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {}
-
- @override
- void declaredFunction(FunctionDeclaration declaration) {
- SimpleIdentifier selector = declaration.name;
- if (selector != null && name == selector.name) {
- _addSuggestions(declaration.functionExpression.parameters);
- finished();
- }
- }
-
- @override
- void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {}
-
- @override
- void declaredLabel(Label label, bool isCaseLabel) {}
-
- @override
- void declaredLocalVar(SimpleIdentifier name, TypeName type) {}
-
- @override
- void declaredMethod(MethodDeclaration declaration) {
- SimpleIdentifier selector = declaration.name;
- if (selector != null && name == selector.name) {
- _addSuggestions(declaration.parameters);
- finished();
- }
- }
-
- @override
- void declaredParam(SimpleIdentifier name, TypeName type) {}
-
- @override
- void declaredTopLevelVar(
- VariableDeclarationList varList, VariableDeclaration varDecl) {}
-
- void _addArgListSuggestion(Iterable<FormalParameter> requiredParam) {
- StringBuffer completion = new StringBuffer('(');
- List<String> paramNames = new List<String>();
- List<String> paramTypes = new List<String>();
- for (FormalParameter param in requiredParam) {
- SimpleIdentifier paramId = param.identifier;
- if (paramId != null) {
- String name = paramId.name;
- if (name != null && name.length > 0) {
- if (completion.length > 1) {
- completion.write(', ');
- }
- completion.write(name);
- paramNames.add(name);
- paramTypes.add(_getParamType(param));
- }
- }
- }
- completion.write(')');
- CompletionSuggestion suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.ARGUMENT_LIST,
- DART_RELEVANCE_HIGH,
- completion.toString(),
- completion.length,
- 0,
- false,
- false);
- suggestion.parameterNames = paramNames;
- suggestion.parameterTypes = paramTypes;
- request.addSuggestion(suggestion);
- }
-
- void _addDefaultParamSuggestions(FormalParameterList parameters) {
- Iterable<String> namedArgs = _namedArgs(request);
- for (FormalParameter param in parameters.parameters) {
- if (param.kind == ParameterKind.NAMED) {
- SimpleIdentifier paramId = param.identifier;
- if (paramId != null) {
- _addNamedParameterSuggestion(request, namedArgs, paramId.name);
- }
- }
- }
- }
-
- void _addSuggestions(FormalParameterList parameters) {
- if (parameters == null || parameters.parameters.length == 0) {
- return;
- }
- Iterable<FormalParameter> requiredParam = parameters.parameters
- .where((FormalParameter p) => p.kind == ParameterKind.REQUIRED);
- int requiredCount = requiredParam.length;
- if (requiredCount > 0 && _isEmptyArgList(request)) {
- _addArgListSuggestion(requiredParam);
- return;
- }
- if (_isAppendingToArgList(request)) {
- if (requiredCount == 0 || requiredCount < _argCount(request)) {
- _addDefaultParamSuggestions(parameters);
- }
- }
- }
-
- String _getParamType(FormalParameter param) {
- TypeName type;
- if (param is SimpleFormalParameter) {
- type = param.type;
- }
- if (type != null) {
- Identifier id = type.name;
- if (id != null) {
- String name = id.name;
- if (name != null && name.length > 0) {
- return name;
- }
- }
- }
- return 'dynamic';
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart b/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
deleted file mode 100644
index a8ef022..0000000
--- a/pkg/analysis_server/lib/src/services/completion/combinator_contributor.dart
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.contributor.dart.combinator;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/protocol_server.dart'
- hide Element, ElementKind;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-
-/**
- * A contributor for calculating `completion.getSuggestions` request results
- * for the import combinators show and hide.
- */
-class CombinatorContributor extends DartCompletionContributor {
- _CombinatorSuggestionBuilder builder;
-
- @override
- bool computeFast(DartCompletionRequest request) {
- builder = request.target.containingNode
- .accept(new _CombinatorAstVisitor(request));
- return builder == null;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- if (builder != null) {
- return builder.execute(request.target.containingNode);
- }
- return new Future.value(false);
- }
-}
-
-/**
- * A visitor for determining which imported classes and top level variables
- * should be suggested and building those suggestions.
- */
-class _CombinatorAstVisitor
- extends GeneralizingAstVisitor<_CombinatorSuggestionBuilder> {
- final DartCompletionRequest request;
-
- _CombinatorAstVisitor(this.request);
-
- @override
- _CombinatorSuggestionBuilder visitCombinator(Combinator node) {
- return new _CombinatorSuggestionBuilder(
- request, CompletionSuggestionKind.IDENTIFIER);
- }
-
- @override
- _CombinatorSuggestionBuilder visitNode(AstNode node) {
- return null;
- }
-}
-
-/**
- * A `_CombinatorSuggestionBuilder` determines which imported classes
- * and top level variables should be suggested and builds those suggestions.
- * This operation is instantiated during `computeFast`
- * and calculates the suggestions during `computeFull`.
- */
-class _CombinatorSuggestionBuilder extends LibraryElementSuggestionBuilder {
- _CombinatorSuggestionBuilder(
- DartCompletionRequest request, CompletionSuggestionKind kind)
- : super(request, kind, false, false);
-
- Future<bool> execute(AstNode node) {
- var directive = node.getAncestor((parent) => parent is NamespaceDirective);
- if (directive is NamespaceDirective) {
- LibraryElement library = directive.uriElement;
- if (library != null) {
- library.visitChildren(this);
- }
- }
- return new Future.value(false);
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index 68fa732..b65f4bf 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -2,9 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library analysis_server.src.services.completion.completion_dart;
+library analysis_server.src.services.completion.completion_core;
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -13,29 +14,24 @@
* The information about a requested list of completions.
*/
class CompletionRequestImpl implements CompletionRequest {
- /**
- * The analysis context in which the completion is being requested.
- */
- AnalysisContext context;
+ @override
+ final AnalysisContext context;
- /**
- * The resource provider associated with this request.
- */
- ResourceProvider resourceProvider;
+ @override
+ final Source source;
- /**
- * The source in which the completion is being requested.
- */
- Source source;
+ @override
+ final int offset;
- /**
- * The offset within the source at which the completion is being requested.
- */
- int offset;
+ @override
+ final ResourceProvider resourceProvider;
+
+ @override
+ final SearchEngine searchEngine;
/**
* Initialize a newly created completion request based on the given arguments.
*/
- CompletionRequestImpl(
- this.context, this.resourceProvider, this.source, this.offset);
+ CompletionRequestImpl(this.context, this.resourceProvider, this.searchEngine,
+ this.source, this.offset);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
deleted file mode 100644
index 1cfff04..0000000
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analysis_server.src.services.completion.completion_dart;
-
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/completion_core.dart';
-import 'package:analyzer/src/generated/ast.dart';
-
-/**
- * The information about a requested list of completions within a Dart file.
- */
-class DartCompletionRequestImpl extends CompletionRequestImpl
- implements DartCompletionRequest {
- /**
- * The compilation unit in which the completion was requested.
- */
- final CompilationUnit unit;
-
- /**
- * A flag indicating whether the compilation [unit] is resolved.
- */
- final bool isResolved;
-
- /**
- * The completion target. This determines what part of the parse tree
- * will receive the newly inserted text.
- */
- final CompletionTarget target;
-
- /**
- * Initialize a newly created completion request based on the given arguments.
- */
- DartCompletionRequestImpl(
- CompletionRequest request, this.unit, this.isResolved, this.target)
- : super(request.context, request.resourceProvider, request.source,
- request.offset);
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index 2ba4340..c559a80 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -7,12 +7,10 @@
import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.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/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -59,14 +57,14 @@
* 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);
@@ -217,30 +215,6 @@
}
/**
- * Encapsulates information specific to a particular completion request.
- */
-class CompletionRequestImpl implements CompletionRequest {
- /**
- * The underlying analysis server for this completion request.
- */
- final AnalysisServer server;
-
- @override
- final AnalysisContext context;
-
- @override
- final Source source;
-
- @override
- final int offset;
-
- CompletionRequestImpl(this.server, this.context, this.source, this.offset);
-
- @override
- ResourceProvider get resourceProvider => server.resourceProvider;
-}
-
-/**
* Code completion result generated by an [CompletionManager].
*/
class CompletionResultImpl implements CompletionResult {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
new file mode 100644
index 0000000..46e20aa
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -0,0 +1,242 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.arglist;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+
+/**
+ * Determine the number of arguments.
+ */
+int _argCount(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ return node.arguments.length;
+ }
+ return 0;
+}
+
+String _getParamType(ParameterElement param) {
+ DartType type = param.type;
+ if (type != null) {
+ return type.displayName;
+ }
+ return 'dynamic';
+}
+
+/**
+ * If the containing [node] is an argument list
+ * or named expression in an argument list
+ * then return the simple identifier for the method, constructor, or annotation
+ * to which the argument list is associated
+ */
+SimpleIdentifier _getTargetId(AstNode node) {
+ if (node is NamedExpression) {
+ return _getTargetId(node.parent);
+ }
+ if (node is ArgumentList) {
+ AstNode parent = node.parent;
+ if (parent is MethodInvocation) {
+ return parent.methodName;
+ }
+ if (parent is InstanceCreationExpression) {
+ ConstructorName constructorName = parent.constructorName;
+ if (constructorName != null) {
+ if (constructorName.name != null) {
+ return constructorName.name;
+ }
+ Identifier typeName = constructorName.type.name;
+ if (typeName is SimpleIdentifier) {
+ return typeName;
+ }
+ if (typeName is PrefixedIdentifier) {
+ return typeName.identifier;
+ }
+ }
+ }
+ if (parent is Annotation) {
+ return parent.constructorName ?? parent.name;
+ }
+ }
+ return null;
+}
+
+/**
+ * Determine if the completion target is at the end of the list of arguments.
+ */
+bool _isAppendingToArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ var entity = request.target.entity;
+ if (entity == node.rightParenthesis) {
+ return true;
+ }
+ if (node.arguments.length > 0 && node.arguments.last == entity) {
+ return entity is SimpleIdentifier;
+ }
+ }
+ return false;
+}
+
+/**
+ * Determine if the completion target is an emtpy argument list.
+ */
+bool _isEmptyArgList(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ return node is ArgumentList &&
+ node.leftParenthesis.next == node.rightParenthesis;
+}
+
+/**
+ * Return a collection of currently specified named arguments
+ */
+Iterable<String> _namedArgs(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ List<String> namedArgs = new List<String>();
+ if (node is ArgumentList) {
+ for (Expression arg in node.arguments) {
+ if (arg is NamedExpression) {
+ namedArgs.add(arg.name.label.name);
+ }
+ }
+ }
+ return namedArgs;
+}
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * when the cursor position is inside the arguments to a method call.
+ */
+class ArgListContributor extends DartCompletionContributor {
+ DartCompletionRequest request;
+ List<CompletionSuggestion> suggestions;
+
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ this.request = request;
+ this.suggestions = <CompletionSuggestion>[];
+
+ // Determine if the target is in an argument list
+ // for a method or a constructor or an annotation
+ // and resolve the identifier
+ SimpleIdentifier targetId = _getTargetId(request.target.containingNode);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the target expression to determine the arguments
+ await request.resolveIdentifier(targetId);
+ // Gracefully degrade if the element could not be resolved
+ // e.g. target changed, completion aborted
+ targetId = _getTargetId(request.target.containingNode);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+ Element elem = targetId.bestElement;
+ if (elem == null) {
+ return EMPTY_LIST;
+ }
+
+ // Generate argument list suggestion based upon the type of element
+ if (elem is ClassElement) {
+ for (ConstructorElement constructor in elem.constructors) {
+ if (!constructor.isFactory) {
+ _addSuggestions(constructor.parameters);
+ return suggestions;
+ }
+ }
+ }
+ if (elem is ConstructorElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+ if (elem is FunctionElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+ if (elem is MethodElement) {
+ _addSuggestions(elem.parameters);
+ return suggestions;
+ }
+ return EMPTY_LIST;
+ }
+
+ void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
+ StringBuffer completion = new StringBuffer('(');
+ List<String> paramNames = new List<String>();
+ List<String> paramTypes = new List<String>();
+ for (ParameterElement param in requiredParam) {
+ String name = param.name;
+ if (name != null && name.length > 0) {
+ if (completion.length > 1) {
+ completion.write(', ');
+ }
+ completion.write(name);
+ paramNames.add(name);
+ paramTypes.add(_getParamType(param));
+ }
+ }
+ completion.write(')');
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.ARGUMENT_LIST,
+ DART_RELEVANCE_HIGH,
+ completion.toString(),
+ completion.length,
+ 0,
+ false,
+ false);
+ suggestion.parameterNames = paramNames;
+ suggestion.parameterTypes = paramTypes;
+ suggestions.add(suggestion);
+ }
+
+ void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters) {
+ Iterable<String> namedArgs = _namedArgs(request);
+ for (ParameterElement param in parameters) {
+ if (param.parameterKind == ParameterKind.NAMED) {
+ _addNamedParameterSuggestion(request, namedArgs, param.name);
+ }
+ }
+ }
+
+ void _addNamedParameterSuggestion(
+ DartCompletionRequest request, List<String> namedArgs, String name) {
+ if (name != null && name.length > 0 && !namedArgs.contains(name)) {
+ suggestions.add(new CompletionSuggestion(
+ CompletionSuggestionKind.NAMED_ARGUMENT,
+ DART_RELEVANCE_NAMED_PARAMETER,
+ '$name: ',
+ name.length + 2,
+ 0,
+ false,
+ false));
+ }
+ }
+
+ void _addSuggestions(Iterable<ParameterElement> parameters) {
+ if (parameters == null || parameters.length == 0) {
+ return;
+ }
+ Iterable<ParameterElement> requiredParam = parameters.where(
+ (ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
+ int requiredCount = requiredParam.length;
+ if (requiredCount > 0 && _isEmptyArgList(request)) {
+ _addArgListSuggestion(requiredParam);
+ return;
+ }
+ if (_isAppendingToArgList(request)) {
+ if (requiredCount == 0 || requiredCount < _argCount(request)) {
+ _addDefaultParamSuggestions(parameters);
+ }
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
new file mode 100644
index 0000000..cba3bd4
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library services.completion.contributor.dart.combinator;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+
+/**
+ * A contributor for calculating `completion.getSuggestions` request results
+ * for the import combinators show and hide.
+ */
+class CombinatorContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ AstNode node = request.target.containingNode;
+ if (node is! Combinator) {
+ return EMPTY_LIST;
+ }
+
+ // Partially resolve the compilation unit
+ CompilationUnit unit = await request.resolveDeclarationsInScope();
+ // Gracefully degrade if the compilation unit could not be resolved
+ // e.g. detached part file or source change
+ if (unit == null) {
+ return EMPTY_LIST;
+ }
+
+ // Check the target since resolution may have changed it
+ node = request.target.containingNode;
+ if (node is! Combinator) {
+ return EMPTY_LIST;
+ }
+
+ // Build list of suggestions
+ var directive = node.getAncestor((parent) => parent is NamespaceDirective);
+ if (directive is NamespaceDirective) {
+ LibraryElement library = directive.uriElement;
+ if (library != null) {
+ LibraryElementSuggestionBuilder builder =
+ new LibraryElementSuggestionBuilder(
+ request, CompletionSuggestionKind.IDENTIFIER, false, false);
+ library.visitChildren(builder);
+ return builder.suggestions;
+ }
+ }
+ return EMPTY_LIST;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
similarity index 90%
rename from pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
index 7351ad0..fde8bfb 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
@@ -2,30 +2,31 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.computer.dart.relevance;
+library services.completion.dart.sorter.common;
+
+import 'dart:async';
import 'package:analysis_server/src/protocol_server.dart' as protocol;
import 'package:analysis_server/src/protocol_server.dart'
show CompletionSuggestion, CompletionSuggestionKind;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
show DART_RELEVANCE_COMMON_USAGE;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
-import 'package:analysis_server/src/provisional/completion/completion_core.dart';
-import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analyzer/task/dart.dart';
import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
-part 'common_usage_generated.dart';
+part 'common_usage_sorter.g.dart';
/**
* A computer for adjusting the relevance of completions computed by others
* based upon common Dart usage patterns. This is a long-lived object
* that should not maintain state between calls to it's [sort] method.
*/
-class CommonUsageComputer implements ContributionSorter {
+class CommonUsageSorter implements DartContributionSorter {
/**
* A map of <library>.<classname> to an ordered list of method names,
* field names, getter names, and named constructors.
@@ -34,13 +35,13 @@
*/
Map<String, List<String>> selectorRelevance;
- CommonUsageComputer([this.selectorRelevance = defaultSelectorRelevance]);
+ CommonUsageSorter([this.selectorRelevance = defaultSelectorRelevance]);
@override
- AnalysisRequest sort(
- CompletionRequest request, Iterable<CompletionSuggestion> suggestions) {
+ Future sort(CompletionRequest request,
+ Iterable<CompletionSuggestion> suggestions) {
_update(request, suggestions);
- return null;
+ return new Future.value();
}
CompletionTarget _getCompletionTarget(CompletionRequest request) {
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
similarity index 99%
rename from pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
index f6899ec..f065701 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_generated.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.g.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of services.completion.computer.dart.relevance;
+part of services.completion.dart.sorter.common;
// Auto-generated, please do not edit.
@@ -424,4 +424,4 @@
'dart.dom.html.Css': const ['supports',],
'dart.io.IOException': const ['toString',],
'dart.dom.html.ButtonInputElement': const ['value','onClick',],
-};
\ No newline at end of file
+};
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
new file mode 100644
index 0000000..6f182d8
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_manager.dart
@@ -0,0 +1,185 @@
+// 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.completion.dart.manager;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+ show CompletionContributor, CompletionRequest;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
+import 'package:analysis_server/src/services/search/search_engine.dart';
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/src/context/context.dart'
+ show AnalysisFutureHelper, AnalysisContextImpl;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/task/dart.dart';
+
+/**
+ * [DartCompletionManager] determines if a completion request is Dart specific
+ * and forwards those requests to all [DartCompletionContributor]s.
+ */
+class DartCompletionManager implements CompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ CompletionRequest request) {
+ if (AnalysisEngine.isDartFileName(request.source.shortName)) {
+ return _computeDartSuggestions(
+ new DartCompletionRequestImpl.forRequest(request));
+ }
+ return new Future.value();
+ }
+
+ /**
+ * Return a [Future] that completes with a list of suggestions
+ * for the given completion [request].
+ */
+ Future<List<CompletionSuggestion>> _computeDartSuggestions(
+ DartCompletionRequest request) async {
+ // Request Dart specific completions from each contributor
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (DartCompletionContributor c in dartCompletionPlugin.contributors) {
+ suggestions.addAll(await c.computeSuggestions(request));
+ }
+ return suggestions;
+ }
+}
+
+/**
+ * The information about a requested list of completions within a Dart file.
+ */
+class DartCompletionRequestImpl extends CompletionRequestImpl
+ implements DartCompletionRequest {
+ /**
+ * The cached completion target or `null` if not computed yet.
+ */
+ CompletionTarget _target;
+
+ /**
+ * `true` if [resolveDeclarationsInScope] has partially resolved the unit
+ * referenced by [target], else `false`.
+ */
+ bool _haveResolveDeclarationsInScope = false;
+
+ /**
+ * Initialize a newly created completion request based on the given request.
+ */
+ factory DartCompletionRequestImpl.forRequest(CompletionRequest request) {
+ return new DartCompletionRequestImpl._(
+ request.context,
+ request.resourceProvider,
+ request.searchEngine,
+ request.source,
+ request.offset);
+ }
+
+ DartCompletionRequestImpl._(
+ AnalysisContext context,
+ ResourceProvider resourceProvider,
+ SearchEngine searchEngine,
+ Source source,
+ int offset)
+ : super(context, resourceProvider, searchEngine, source, offset);
+
+ @override
+ CompletionTarget get target {
+ if (_target == null) {
+ CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
+ _target = new CompletionTarget.forOffset(unit, offset);
+ }
+ return _target;
+ }
+
+ @override
+ Future<CompilationUnit> resolveDeclarationsInScope() async {
+ CompilationUnit unit = target.unit;
+ if (_haveResolveDeclarationsInScope) {
+ return unit;
+ }
+
+ // Determine the library source
+ Source librarySource;
+ if (unit.directives.any((d) => d is PartOfDirective)) {
+ List<Source> libraries = context.getLibrariesContaining(source);
+ if (libraries.isEmpty) {
+ return null;
+ }
+ librarySource = libraries[0];
+ } else {
+ librarySource = source;
+ }
+
+ // Resolve declarations in the target unit
+ CompilationUnit resolvedUnit =
+ await new AnalysisFutureHelper<CompilationUnit>(
+ context,
+ new LibrarySpecificUnit(librarySource, source),
+ RESOLVED_UNIT3).computeAsync();
+
+ // TODO(danrubel) determine if the underlying source has been modified
+ // in a way that invalidates the completion request
+ // and return null
+
+ // Gracefully degrade if unit cannot be resolved
+ if (resolvedUnit == null) {
+ return null;
+ }
+
+ // Recompute the target for the newly resolved unit
+ _target = new CompletionTarget.forOffset(resolvedUnit, offset);
+ _haveResolveDeclarationsInScope = true;
+ return resolvedUnit;
+ }
+
+ @override
+ Future resolveIdentifier(SimpleIdentifier identifier) async {
+ if (identifier.bestElement != null) {
+ return;
+ }
+
+ //TODO(danrubel) resolve the expression or containing method
+ // rather than the entire complilation unit
+
+ CompilationUnit unit = target.unit;
+
+ // Determine the library source
+ Source librarySource;
+ if (unit.directives.any((d) => d is PartOfDirective)) {
+ List<Source> libraries = context.getLibrariesContaining(source);
+ if (libraries.isEmpty) {
+ return;
+ }
+ librarySource = libraries[0];
+ } else {
+ librarySource = source;
+ }
+
+ // Resolve declarations in the target unit
+ CompilationUnit resolvedUnit =
+ await new AnalysisFutureHelper<CompilationUnit>(
+ context,
+ new LibrarySpecificUnit(librarySource, source),
+ RESOLVED_UNIT).computeAsync();
+
+ // TODO(danrubel) determine if the underlying source has been modified
+ // in a way that invalidates the completion request
+ // and return null
+
+ // Gracefully degrade if unit cannot be resolved
+ if (resolvedUnit == null) {
+ return;
+ }
+
+ // Recompute the target for the newly resolved unit
+ _target = new CompletionTarget.forOffset(resolvedUnit, offset);
+ _haveResolveDeclarationsInScope = true;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
similarity index 64%
rename from pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
index cc7b457..8279be3 100644
--- a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/contribution_sorter.dart
@@ -2,26 +2,25 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.sorter;
+library services.completion.dart.sorter;
+
+import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart';
/**
- * The abstract class `ContributionSorter` defines the behavior of objects
+ * The abstract class [DartContributionSorter] defines the behavior of objects
* that are used to adjust the relevance of an existing list of suggestions.
* This is a long-lived object that should not maintain state between
* calls to it's [sort] method.
*/
-abstract class ContributionSorter {
+abstract class DartContributionSorter {
/**
* After [CompletionSuggestion]s have been computed,
* this method is called to adjust the relevance of those suggestions.
- * Return an [AnalysisRequest] if more analysis is needed,
- * or `null` if suggestion sorting is complete.
- * This method should execute quickly and not block.
+ * Return a [Future] that completes when the suggestions have been updated.
*/
- AnalysisRequest sort(
+ Future sort(
CompletionRequest request, Iterable<CompletionSuggestion> suggestions);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
new file mode 100644
index 0000000..fdfb353
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
@@ -0,0 +1,171 @@
+// 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.completion.dart.invocation;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
+import 'package:analysis_server/src/protocol_server.dart' as protocol
+ hide CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * A completion contributor used to suggest replacing partial identifiers inside
+ * a class declaration with templates for inherited members.
+ */
+class InheritedContributor implements DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ // Determine if the target looks like a partial identifier
+ // inside a class declaration
+ SimpleIdentifier targetId = _getTargetId(request.target);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+
+ // Partially resolve the compilation unit
+ CompilationUnit unit = await request.resolveDeclarationsInScope();
+ // Gracefully degrade if the compilation unit could not be resolved
+ // e.g. detached part file or source change
+ if (unit == null) {
+ return EMPTY_LIST;
+ }
+
+ // Recompute the target since resolution may have changed it
+ targetId = _getTargetId(request.target);
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+ ClassDeclaration classDecl =
+ targetId.getAncestor((p) => p is ClassDeclaration);
+ if (classDecl == null) {
+ return EMPTY_LIST;
+ }
+
+ // Generate a collection of inherited members
+ ClassElement classElem = classDecl.element;
+ InheritanceManager manager = new InheritanceManager(classElem.library);
+ MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(classElem);
+ List<String> memberNames = _computeMemberNames(map, classElem);
+
+ // Build suggestions
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (String memberName in memberNames) {
+ ExecutableElement element = map.get(memberName);
+ // Gracefully degrade if the overridden element has not been resolved.
+ if (element.returnType != null) {
+ CompletionSuggestion suggestion =
+ _buildSuggestion(request, targetId, unit, element);
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ }
+ return suggestions;
+ }
+
+ /**
+ * If the target looks like a partial identifier inside a class declaration
+ * then return that identifier, otherwise return `null`.
+ */
+ SimpleIdentifier _getTargetId(CompletionTarget target) {
+ AstNode node = target.containingNode;
+ if (node is ClassDeclaration) {
+ Object entity = target.entity;
+ if (entity is FieldDeclaration) {
+ NodeList<VariableDeclaration> variables = entity.fields.variables;
+ if (variables.length == 1) {
+ SimpleIdentifier targetId = variables[0].name;
+ if (targetId.name.isEmpty) {
+ return targetId;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return a template for an override of the given [element] in the given
+ * [source]. If selected, the template will replace [targetId].
+ */
+ String _buildRepacementText(Source source, SimpleIdentifier targetId,
+ CompilationUnit unit, ExecutableElement element) {
+ // AnalysisContext context = element.context;
+ // Inject partially resolved unit for use by change builder
+ // DartChangeBuilder builder = new DartChangeBuilder(context, unit);
+ // builder.addFileEdit(source, context.getModificationStamp(source),
+ // (DartFileEditBuilder builder) {
+ // builder.addReplacement(targetId.offset, targetId.length,
+ // (DartEditBuilder builder) {
+ // builder.writeOverrideOfInheritedMember(element);
+ // });
+ // });
+ // return builder.sourceChange.edits[0].edits[0].replacement.trim();
+ return '';
+ }
+
+ /**
+ * Build a suggestion to replace [targetId] in the given [unit]
+ * with an override of the given [element].
+ */
+ CompletionSuggestion _buildSuggestion(
+ DartCompletionRequest request,
+ SimpleIdentifier targetId,
+ CompilationUnit unit,
+ ExecutableElement element) {
+ String completion =
+ _buildRepacementText(request.source, targetId, unit, element);
+ if (completion == null || completion.length == 0) {
+ return null;
+ }
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ CompletionSuggestionKind.IDENTIFIER,
+ DART_RELEVANCE_HIGH,
+ completion,
+ targetId.offset,
+ 0,
+ element.isDeprecated,
+ false);
+ suggestion.element = protocol.convertElement(element);
+ return suggestion;
+ }
+
+ /**
+ * Return a list containing the names of all of the inherited but not
+ * implemented members of the class represented by the given [element].
+ * The [map] is used to find all of the members that are inherited.
+ */
+ List<String> _computeMemberNames(MemberMap map, ClassElement element) {
+ List<String> memberNames = <String>[];
+ int count = map.size;
+ for (int i = 0; i < count; i++) {
+ String memberName = map.getKey(i);
+ if (!_hasMember(element, memberName)) {
+ memberNames.add(memberName);
+ }
+ }
+ return memberNames;
+ }
+
+ /**
+ * Return `true` if the given [classElement] directly declares a member with
+ * the given [memberName].
+ */
+ bool _hasMember(ClassElement classElement, String memberName) {
+ return classElement.getField(memberName) != null ||
+ classElement.getGetter(memberName) != null ||
+ classElement.getMethod(memberName) != null ||
+ classElement.getSetter(memberName) != null;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
similarity index 94%
rename from pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 0da2c8c..57beb27 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -3,12 +3,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library services.completion.contributor.dart.keyword;
+library services.completion.dart.keyword;
import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/scanner.dart';
@@ -21,16 +21,15 @@
*/
class KeywordContributor extends DartCompletionContributor {
@override
- bool computeFast(DartCompletionRequest request) {
- if (!request.target.isCommentText) {
- request.target.containingNode.accept(new _KeywordVisitor(request));
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ if (request.target.isCommentText) {
+ return EMPTY_LIST;
}
- return true;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- return new Future.value(false);
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ request.target.containingNode
+ .accept(new _KeywordVisitor(request, suggestions));
+ return suggestions;
}
}
@@ -40,8 +39,9 @@
class _KeywordVisitor extends GeneralizingAstVisitor {
final DartCompletionRequest request;
final Object entity;
+ final List<CompletionSuggestion> suggestions;
- _KeywordVisitor(DartCompletionRequest request)
+ _KeywordVisitor(DartCompletionRequest request, this.suggestions)
: this.request = request,
this.entity = request.target.entity;
@@ -468,14 +468,8 @@
if (offset == null) {
offset = completion.length;
}
- request.addSuggestion(new CompletionSuggestion(
- CompletionSuggestionKind.KEYWORD,
- relevance,
- completion,
- offset,
- 0,
- false,
- false));
+ suggestions.add(new CompletionSuggestion(CompletionSuggestionKind.KEYWORD,
+ relevance, completion, offset, 0, false, false));
}
void _addSuggestions(List<Keyword> keywords,
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
new file mode 100644
index 0000000..fa0cf95
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -0,0 +1,262 @@
+// 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.completion.dart.suggestion.builder;
+
+import 'package:analysis_server/src/protocol_server.dart' as protocol;
+import 'package:analysis_server/src/protocol_server.dart'
+ hide Element, ElementKind;
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:path/path.dart' as path;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+
+const String DYNAMIC = 'dynamic';
+
+/**
+ * Return a suggestion based upon the given element
+ * or `null` if a suggestion is not appropriate for the given element.
+ * If the suggestion is not currently in scope, then specify
+ * importForSource as the source to which an import should be added.
+ */
+CompletionSuggestion createSuggestion(Element element,
+ {String completion,
+ CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+ int relevance: DART_RELEVANCE_DEFAULT,
+ Source importForSource}) {
+ if (element is ExecutableElement && element.isOperator) {
+ // Do not include operators in suggestions
+ return null;
+ }
+ if (completion == null) {
+ completion = element.displayName;
+ }
+ bool isDeprecated = element.isDeprecated;
+ CompletionSuggestion suggestion = new CompletionSuggestion(
+ kind,
+ isDeprecated ? DART_RELEVANCE_LOW : relevance,
+ completion,
+ completion.length,
+ 0,
+ isDeprecated,
+ false);
+ suggestion.element = protocol.convertElement(element);
+ Element enclosingElement = element.enclosingElement;
+ if (enclosingElement is ClassElement) {
+ suggestion.declaringType = enclosingElement.displayName;
+ }
+ suggestion.returnType = getReturnTypeString(element);
+ if (element is ExecutableElement && element is! PropertyAccessorElement) {
+ suggestion.parameterNames = element.parameters
+ .map((ParameterElement parameter) => parameter.name)
+ .toList();
+ suggestion.parameterTypes =
+ element.parameters.map((ParameterElement parameter) {
+ DartType paramType = parameter.type;
+ // Gracefully degrade if type not resolved yet
+ return paramType != null ? paramType.displayName : 'var';
+ }).toList();
+ suggestion.requiredParameterCount = element.parameters
+ .where((ParameterElement parameter) =>
+ parameter.parameterKind == ParameterKind.REQUIRED)
+ .length;
+ suggestion.hasNamedParameters = element.parameters.any(
+ (ParameterElement parameter) =>
+ parameter.parameterKind == ParameterKind.NAMED);
+ }
+ if (importForSource != null) {
+ String srcPath = path.dirname(importForSource.fullName);
+ LibraryElement libElem = element.library;
+ if (libElem != null) {
+ Source libSource = libElem.source;
+ if (libSource != null) {
+ UriKind uriKind = libSource.uriKind;
+ if (uriKind == UriKind.DART_URI) {
+ suggestion.importUri = libSource.uri.toString();
+ } else if (uriKind == UriKind.PACKAGE_URI) {
+ suggestion.importUri = libSource.uri.toString();
+ } else if (uriKind == UriKind.FILE_URI &&
+ element.source.uriKind == UriKind.FILE_URI) {
+ try {
+ suggestion.importUri =
+ path.relative(libSource.fullName, from: srcPath);
+ } catch (_) {
+ // ignored
+ }
+ }
+ }
+ }
+ if (suggestion.importUri == null) {
+ // Do not include out of scope suggestions
+ // for which we cannot determine an import
+ return null;
+ }
+ }
+ return suggestion;
+}
+
+/**
+ * Common mixin for sharing behavior
+ */
+abstract class ElementSuggestionBuilder {
+ /**
+ * A collection of completion suggestions.
+ */
+ final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+
+ /**
+ * Return the kind of suggestions that should be built.
+ */
+ CompletionSuggestionKind get kind;
+
+ /**
+ * Return the request on which the builder is operating.
+ */
+ DartCompletionRequest get request;
+
+ /**
+ * Add a suggestion based upon the given element.
+ */
+ void addSuggestion(Element element,
+ {String prefix, int relevance: DART_RELEVANCE_DEFAULT}) {
+ if (element.isPrivate) {
+ LibraryElement elementLibrary = element.library;
+ CompilationUnitElement unitElem = request.target.unit.element;
+ if (unitElem == null) {
+ return;
+ }
+ LibraryElement unitLibrary = unitElem.library;
+ if (elementLibrary != unitLibrary) {
+ return;
+ }
+ }
+ if (prefix == null && element.isSynthetic) {
+ if ((element is PropertyAccessorElement) ||
+ element is FieldElement && !_isSpecialEnumField(element)) {
+ return;
+ }
+ }
+ String completion = element.displayName;
+ if (prefix != null && prefix.length > 0) {
+ if (completion == null || completion.length <= 0) {
+ completion = prefix;
+ } else {
+ completion = '$prefix.$completion';
+ }
+ }
+ if (completion == null || completion.length <= 0) {
+ return;
+ }
+ CompletionSuggestion suggestion = createSuggestion(element,
+ completion: completion, kind: kind, relevance: relevance);
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+
+ /**
+ * Determine if the given element is one of the synthetic enum accessors
+ * for which we should generate a suggestion.
+ */
+ bool _isSpecialEnumField(FieldElement element) {
+ Element parent = element.enclosingElement;
+ if (parent is ClassElement && parent.isEnum) {
+ if (element.name == 'values') {
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * This class visits elements in a library and provides suggestions based upon
+ * the visible members in that library. Clients should call
+ * [LibraryElementSuggestionBuilder.suggestionsFor].
+ */
+class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor
+ with ElementSuggestionBuilder {
+ final DartCompletionRequest request;
+ final CompletionSuggestionKind kind;
+ final bool typesOnly;
+ final bool instCreation;
+
+ LibraryElementSuggestionBuilder(
+ this.request, this.kind, this.typesOnly, this.instCreation);
+
+ @override
+ visitClassElement(ClassElement element) {
+ if (instCreation) {
+ element.visitChildren(this);
+ } else {
+ addSuggestion(element);
+ }
+ }
+
+ @override
+ visitCompilationUnitElement(CompilationUnitElement element) {
+ element.visitChildren(this);
+ LibraryElement containingLibrary = element.library;
+ if (containingLibrary != null) {
+ for (var lib in containingLibrary.exportedLibraries) {
+ lib.visitChildren(this);
+ }
+ }
+ }
+
+ @override
+ visitConstructorElement(ConstructorElement element) {
+ if (instCreation) {
+ ClassElement classElem = element.enclosingElement;
+ if (classElem != null) {
+ String prefix = classElem.name;
+ if (prefix != null && prefix.length > 0) {
+ addSuggestion(element, prefix: prefix);
+ }
+ }
+ }
+ }
+
+ @override
+ visitElement(Element element) {
+ // ignored
+ }
+
+ @override
+ visitFunctionElement(FunctionElement element) {
+ if (!typesOnly) {
+ addSuggestion(element);
+ }
+ }
+
+ @override
+ visitFunctionTypeAliasElement(FunctionTypeAliasElement element) {
+ if (!instCreation) {
+ addSuggestion(element);
+ }
+ }
+
+ @override
+ visitTopLevelVariableElement(TopLevelVariableElement element) {
+ if (!typesOnly) {
+ addSuggestion(element);
+ }
+ }
+
+ /**
+ * Add suggestions for the visible members in the given library
+ */
+ static void suggestionsFor(
+ DartCompletionRequest request,
+ CompletionSuggestionKind kind,
+ LibraryElement library,
+ bool typesOnly,
+ bool instCreation) {
+ if (library != null) {
+ library.visitChildren(new LibraryElementSuggestionBuilder(
+ request, kind, typesOnly, instCreation));
+ }
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
similarity index 86%
rename from pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
rename to pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
index c6b20d3..ebf87fe 100644
--- a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
@@ -7,7 +7,7 @@
import 'dart:async';
import 'dart:core' hide Resource;
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/sdk.dart';
@@ -15,7 +15,7 @@
import 'package:path/path.dart' show posix;
import 'package:path/src/context.dart';
-import '../../protocol_server.dart'
+import '../../../protocol_server.dart'
show CompletionSuggestion, CompletionSuggestionKind;
/**
@@ -26,27 +26,20 @@
_UriSuggestionBuilder builder;
@override
- bool computeFast(DartCompletionRequest request) {
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
builder = new _UriSuggestionBuilder(request);
- return builder.computeFast(request.target.containingNode);
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- return new Future.value(false);
+ request.target.containingNode.accept(builder);
+ return builder.suggestions;
}
}
class _UriSuggestionBuilder extends SimpleAstVisitor {
final DartCompletionRequest request;
+ final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
_UriSuggestionBuilder(this.request);
- bool computeFast(AstNode node) {
- node.accept(this);
- return true;
- }
-
@override
visitExportDirective(ExportDirective node) {
visitNamespaceDirective(node);
@@ -179,24 +172,15 @@
void _addSuggestion(String completion,
{int relevance: DART_RELEVANCE_DEFAULT}) {
- request.addSuggestion(new CompletionSuggestion(
- CompletionSuggestionKind.IMPORT,
- relevance,
- completion,
- completion.length,
- 0,
- false,
- false));
+ suggestions.add(new CompletionSuggestion(CompletionSuggestionKind.IMPORT,
+ relevance, completion, completion.length, 0, false, false));
}
String _extractPartialUri(SimpleStringLiteral node) {
if (request.offset < node.contentsOffset) {
return null;
}
- String partial = node.literal.lexeme.substring(
+ return node.literal.lexeme.substring(
node.contentsOffset - node.offset, request.offset - node.offset);
- request.replacementOffset = node.contentsOffset;
- request.replacementLength = node.contentsEnd - node.contentsOffset;
- return partial;
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 2edb62a..06bbe66 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -7,51 +7,43 @@
import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart'
- show AnalysisRequest, CompletionRequest;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
- as newApi;
+ show AnalysisRequest, CompletionContributor, CompletionRequest;
import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
-import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
+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/contribution_sorter.dart';
+import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
+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';
-import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
import 'package:analysis_server/src/services/completion/local_reference_contributor.dart';
import 'package:analysis_server/src/services/completion/optype.dart';
import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
-import 'package:analysis_server/src/services/completion/uri_contributor.dart';
import 'package:analysis_server/src/services/search/search_engine.dart';
import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/cancelable_future.dart';
-import 'package:analyzer/src/context/context.dart'
- show AnalysisFutureHelper, AnalysisContextImpl;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/task/model.dart';
-const int DART_RELEVANCE_COMMON_USAGE = 1200;
-const int DART_RELEVANCE_DEFAULT = 1000;
-const int DART_RELEVANCE_HIGH = 2000;
-const int DART_RELEVANCE_INHERITED_ACCESSOR = 1057;
-const int DART_RELEVANCE_INHERITED_FIELD = 1058;
-const int DART_RELEVANCE_INHERITED_METHOD = 1057;
-const int DART_RELEVANCE_KEYWORD = 1055;
-const int DART_RELEVANCE_LOCAL_ACCESSOR = 1057;
-const int DART_RELEVANCE_LOCAL_FIELD = 1058;
-const int DART_RELEVANCE_LOCAL_FUNCTION = 1056;
-const int DART_RELEVANCE_LOCAL_METHOD = 1057;
-const int DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE = 1056;
-const int DART_RELEVANCE_LOCAL_VARIABLE = 1059;
-const int DART_RELEVANCE_LOW = 500;
-const int DART_RELEVANCE_NAMED_PARAMETER = 1060;
-const int DART_RELEVANCE_PARAMETER = 1059;
+export 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart'
+ show
+ DART_RELEVANCE_COMMON_USAGE,
+ DART_RELEVANCE_DEFAULT,
+ DART_RELEVANCE_HIGH,
+ DART_RELEVANCE_INHERITED_ACCESSOR,
+ DART_RELEVANCE_INHERITED_FIELD,
+ DART_RELEVANCE_INHERITED_METHOD,
+ DART_RELEVANCE_KEYWORD,
+ DART_RELEVANCE_LOCAL_ACCESSOR,
+ DART_RELEVANCE_LOCAL_FIELD,
+ DART_RELEVANCE_LOCAL_FUNCTION,
+ DART_RELEVANCE_LOCAL_METHOD,
+ DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE,
+ DART_RELEVANCE_LOCAL_VARIABLE,
+ DART_RELEVANCE_LOW,
+ DART_RELEVANCE_NAMED_PARAMETER,
+ DART_RELEVANCE_PARAMETER;
/**
* The base class for contributing code completion suggestions.
@@ -84,17 +76,18 @@
* The [defaultContributionSorter] is a long-lived object that isn't allowed
* to maintain state between calls to [ContributionSorter#sort(...)].
*/
- static ContributionSorter defaultContributionSorter =
- new CommonUsageComputer();
+ static DartContributionSorter defaultContributionSorter =
+ new CommonUsageSorter();
final SearchEngine searchEngine;
final DartCompletionCache cache;
List<DartCompletionContributor> contributors;
- ContributionSorter contributionSorter;
+ Iterable<CompletionContributor> newContributors;
+ DartContributionSorter contributionSorter;
DartCompletionManager(
AnalysisContext context, this.searchEngine, Source source, this.cache,
- [this.contributors, this.contributionSorter])
+ [this.contributors, this.newContributors, this.contributionSorter])
: super(context, source) {
if (contributors == null) {
contributors = [
@@ -103,16 +96,19 @@
// and can hide other suggestions with the same name
new LocalReferenceContributor(),
new ImportedReferenceContributor(),
- new KeywordContributor(),
- new ArgListContributor(),
- new CombinatorContributor(),
+ //new KeywordContributor(),
+ //new ArgListContributor(),
+ // new CombinatorContributor(),
new PrefixedElementContributor(),
- new UriContributor(),
+ //new UriContributor(),
// TODO(brianwilkerson) Use the completion contributor extension point
// to add the contributor below (and eventually, all the contributors).
// new NewCompletionWrapper(new InheritedContributor())
];
}
+ if (newContributors == null) {
+ newContributors = <CompletionContributor>[];
+ }
if (contributionSorter == null) {
contributionSorter = defaultContributionSorter;
}
@@ -122,9 +118,12 @@
* 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
@@ -145,39 +144,21 @@
*/
List<DartCompletionContributor> computeFast(
DartCompletionRequest request, CompletionPerformance performance) {
- bool isKeywordOrIdentifier(Token token) =>
- token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
-
return performance.logElapseTime('computeFast', () {
CompilationUnit unit = context.parseCompilationUnit(source);
request.unit = unit;
request.target = new CompletionTarget.forOffset(unit, request.offset);
- request.replacementOffset = request.offset;
- request.replacementLength = 0;
if (request.offset < 0 || request.offset > unit.end) {
+ request.replacementOffset = request.offset;
+ request.replacementLength = 0;
sendResults(request, true);
return [];
}
- var entity = request.target.entity;
- Token token = entity is AstNode ? entity.beginToken : entity;
- if (token != null && request.offset < token.offset) {
- token = token.previous;
- }
- if (token != null) {
- if (request.offset == token.offset && !isKeywordOrIdentifier(token)) {
- // If the insertion point is at the beginning of the current token
- // and the current token is not an identifier
- // then check the previous token to see if it should be replaced
- token = token.previous;
- }
- if (token != null && isKeywordOrIdentifier(token)) {
- if (token.offset <= request.offset && request.offset <= token.end) {
- request.replacementOffset = token.offset;
- request.replacementLength = token.length;
- }
- }
- }
+ ReplacementRange range =
+ new ReplacementRange.compute(request.offset, request.target);
+ request.replacementOffset = range.offset;
+ request.replacementLength = range.length;
List<DartCompletionContributor> todo = new List.from(contributors);
todo.removeWhere((DartCompletionContributor c) {
@@ -185,14 +166,6 @@
return c.computeFast(request);
});
});
- _processAnalysisRequest(request,
- contributionSorter.sort(request, request.suggestions));
- // TODO (danrubel) if request is obsolete
- // (processAnalysisRequest returns false)
- // then send empty results
- if (todo.isEmpty) {
- sendResults(request, todo.isEmpty);
- }
return todo;
});
}
@@ -202,9 +175,38 @@
* resolved and request that each remaining contributor finish their work.
* Return a [Future] that completes when the last notification has been sent.
*/
- Future computeFull(DartCompletionRequest request,
- CompletionPerformance performance, List<DartCompletionContributor> todo) {
+ Future computeFull(
+ DartCompletionRequest request,
+ CompletionPerformance performance,
+ List<DartCompletionContributor> todo) async {
+ // Compute suggestions using the new API
+ performance.logStartTime('computeSuggestions');
+ for (CompletionContributor contributor in newContributors) {
+ String contributorTag = 'computeSuggestions - ${contributor.runtimeType}';
+ performance.logStartTime(contributorTag);
+ List<CompletionSuggestion> newSuggestions =
+ await contributor.computeSuggestions(request);
+ for (CompletionSuggestion suggestion in newSuggestions) {
+ request.addSuggestion(suggestion);
+ }
+ performance.logElapseTime(contributorTag);
+ }
+ performance.logElapseTime('computeSuggestions');
performance.logStartTime('waitForAnalysis');
+
+ if (todo.isEmpty) {
+ // TODO(danrubel) current sorter requires no additional analysis,
+ // but need to handle the returned future the same way that futures
+ // returned from contributors are handled once this method is refactored
+ // to be async.
+ /* await */ contributionSorter.sort(request, request.suggestions);
+ // TODO (danrubel) if request is obsolete
+ // (processAnalysisRequest returns false)
+ // then send empty results
+ sendResults(request, true);
+ }
+
+ // Compute the other suggestions
return waitForAnalysis().then((CompilationUnit unit) {
if (controller.isClosed) {
return;
@@ -229,8 +231,12 @@
performance.logElapseTime(completeTag);
bool last = --count == 0;
if (changed || last) {
- _processAnalysisRequest(request,
- contributionSorter.sort(request, request.suggestions));
+ // TODO(danrubel) current sorter requires no additional analysis,
+ // but need to handle the returned future the same way that futures
+ // returned from contributors are handled once this method is refactored
+ // to be async.
+ /* await */ contributionSorter.sort(
+ request, request.suggestions);
// TODO (danrubel) if request is obsolete
// (processAnalysisRequest returns false)
// then send empty results
@@ -250,9 +256,7 @@
CompletionPerformance performance = new CompletionPerformance();
performance.logElapseTime('compute', () {
List<DartCompletionContributor> todo = computeFast(request, performance);
- if (!todo.isEmpty) {
- computeFull(request, performance, todo);
- }
+ computeFull(request, performance, todo);
});
}
@@ -291,38 +295,6 @@
return null;
}, test: (e) => e is AnalysisNotScheduledError);
}
-
- /**
- * Process the analysis [analysis] and any subsequent requests.
- * Return a [Future] that returns `true`
- * once all analysis requests have been processed
- * or `false` if the original completion request is obsolete
- * and processing requests was terminated before finished.
- */
- Future<bool> _processAnalysisRequest(
- CompletionRequest request, AnalysisRequest analysis) {
- // Return if no additional analysis is necessary
- if (analysis == null) {
- return new Future.value(true);
- }
-
- // Check to see if the result is already cached
- var cachedValue = context.getResult(analysis.target, analysis.descriptor);
- if (cachedValue != null) {
- return _processAnalysisRequest(
- request, analysis.callback(request, cachedValue));
- }
-
- // TODO (danrubel) determine when completion request is obsolete
- // and analysis should be terminated before requesting additional analysis
-
- // Request additional analysis
- return new AnalysisFutureHelper((context as AnalysisContextImpl),
- analysis.target, analysis.descriptor).computeAsync().then((value) {
- return _processAnalysisRequest(
- request, analysis.callback(request, cachedValue));
- });
- }
}
/**
@@ -378,14 +350,19 @@
*/
final Set<String> _completions = new Set<String>();
- DartCompletionRequest(AnalysisServer server, AnalysisContext context,
- Source source, int offset, this.cache)
- : super(server, context, source, offset);
+ DartCompletionRequest(
+ AnalysisContext context,
+ ResourceProvider resourceProvider,
+ SearchEngine searchEngine,
+ Source source,
+ int offset,
+ this.cache)
+ : super(context, resourceProvider, searchEngine, source, offset);
factory DartCompletionRequest.from(
CompletionRequestImpl request, DartCompletionCache cache) =>
- new DartCompletionRequest(request.server, request.context, request.source,
- request.offset, cache);
+ new DartCompletionRequest(request.context, request.resourceProvider,
+ request.searchEngine, request.source, request.offset, cache);
/**
* Return the original text from the [replacementOffset] to the [offset]
@@ -410,11 +387,6 @@
}
/**
- * The search engine for use when building suggestions.
- */
- SearchEngine get searchEngine => server.searchEngine;
-
- /**
* The list of suggestions to be sent to the client.
*/
Iterable<CompletionSuggestion> get suggestions => _suggestions;
@@ -461,80 +433,58 @@
}
/**
- * A wrapper around a new dart completion contributor that makes it usable where
- * an old dart completion contributor is expected.
+ * Utility class for computing the code completion replacement range
*/
-class NewCompletionWrapper implements DartCompletionContributor {
- /**
- * The new-style contributor that is being wrapped.
- */
- final newApi.DartCompletionContributor contributor;
+class ReplacementRange {
+ int offset;
+ int length;
- /**
- * Initialize a newly created wrapper for the given [contributor].
- */
- NewCompletionWrapper(this.contributor);
+ ReplacementRange(this.offset, this.length);
- @override
- bool computeFast(DartCompletionRequest request) {
- List<CompletionSuggestion> suggestions =
- contributor.computeSuggestions(new OldRequestWrapper(request));
- if (suggestions == null) {
- return false;
+ factory ReplacementRange.compute(int requestOffset, CompletionTarget target) {
+ bool isKeywordOrIdentifier(Token token) =>
+ token.type == TokenType.KEYWORD || token.type == TokenType.IDENTIFIER;
+
+ //TODO(danrubel) Ideally this needs to be pushed down into the contributors
+ // but that implies that each suggestion can have a different
+ // replacement offsent/length which would mean an API change
+
+ var entity = target.entity;
+ Token token = entity is AstNode ? entity.beginToken : entity;
+ if (token != null && requestOffset < token.offset) {
+ token = token.previous;
}
- for (CompletionSuggestion suggestion in suggestions) {
- request.addSuggestion(suggestion);
- }
- return true;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) async {
- List<CompletionSuggestion> suggestions =
- contributor.computeSuggestions(new OldRequestWrapper(request));
- if (suggestions != null) {
- for (CompletionSuggestion suggestion in suggestions) {
- request.addSuggestion(suggestion);
+ if (token != null) {
+ if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) {
+ // If the insertion point is at the beginning of the current token
+ // and the current token is not an identifier
+ // then check the previous token to see if it should be replaced
+ token = token.previous;
}
- return true;
+ if (token != null && isKeywordOrIdentifier(token)) {
+ if (token.offset <= requestOffset && requestOffset <= token.end) {
+ // Replacement range for typical identifier completion
+ return new ReplacementRange(token.offset, token.length);
+ }
+ }
+ if (token is StringToken) {
+ SimpleStringLiteral uri = new SimpleStringLiteral(token, token.lexeme);
+ Token previous = token.previous;
+ if (previous is KeywordToken) {
+ Keyword keyword = previous.keyword;
+ if (keyword == Keyword.IMPORT ||
+ keyword == Keyword.EXPORT ||
+ keyword == Keyword.PART) {
+ int start = uri.contentsOffset;
+ var end = uri.contentsEnd;
+ if (start <= requestOffset && requestOffset <= end) {
+ // Replacement range for import URI
+ return new ReplacementRange(start, end - start);
+ }
+ }
+ }
+ }
}
- return false;
+ return new ReplacementRange(requestOffset, 0);
}
-
- @override
- String toString() => 'wrapped $contributor';
-}
-
-/**
- * A wrapper around an old dart completion request that makes it usable where a
- * new dart completion request is expected.
- */
-class OldRequestWrapper implements newApi.DartCompletionRequest {
- final DartCompletionRequest request;
-
- OldRequestWrapper(this.request);
-
- @override
- AnalysisContext get context => request.context;
-
- @override
- bool get isResolved => request.unit.element != null;
-
- @override
- int get offset => request.offset;
-
- @override
- ResourceProvider get resourceProvider => request.resourceProvider;
-
- @override
- Source get source => request.source;
-
- @override
- CompletionTarget get target => request.target;
-
- @override
- CompilationUnit get unit => request.unit;
-
- @override
- String toString() => 'wrapped $request';
}
diff --git a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
deleted file mode 100644
index 451da53..0000000
--- a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
+++ /dev/null
@@ -1,160 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library services.completion.computer.dart.invocation;
-
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
-import 'package:analysis_server/src/protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
-import 'package:analysis_server/src/protocol_server.dart' as protocol
- hide CompletionSuggestion, CompletionSuggestionKind;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
- show DART_RELEVANCE_HIGH;
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart';
-
-/**
- * A completion contributor used to suggest replacing partial identifiers inside
- * a class declaration with templates for inherited members.
- */
-class InheritedContributor extends DartCompletionContributor {
- @override
- List<CompletionSuggestion> internalComputeSuggestions(
- DartCompletionRequest request) {
- if (!request.isResolved) {
- return null;
- }
- AstNode node = new NodeLocator(request.offset).searchWithin(request.unit);
- if (node == null || !_isMemberLevelIdentifier(node)) {
- return null;
- }
- ClassDeclaration classDeclaration =
- node.getAncestor((AstNode node) => node is ClassDeclaration);
- if (classDeclaration != null) {
- ClassElement element = classDeclaration.element;
- if (element == null) {
- return null;
- }
- return _suggestInheritedMembers(request, node, element);
- }
- return null;
- }
-
- /**
- * Return a template for an override of the given [element] in the given
- * [source]. If selected, the template will replace the given [identifier].
- */
- String _buildRepacementText(
- Source source, SimpleIdentifier identifier, Element element) {
- AnalysisContext context = element.context;
- DartChangeBuilder builder = new DartChangeBuilder(context);
- builder.addFileEdit(source, context.getModificationStamp(source),
- (DartFileEditBuilder builder) {
- builder.addReplacement(identifier.offset, identifier.length,
- (DartEditBuilder builder) {
- builder.writeOverrideOfInheritedMember(element);
- });
- });
- return builder.sourceChange.edits[0].edits[0].replacement.trim();
- }
-
- /**
- * Build a suggestion to replace the partial [identifier] in the given
- * [source] with an override of the given [element].
- */
- CompletionSuggestion _buildSuggestion(
- Source source, SimpleIdentifier identifier, Element element) {
- String completion = _buildRepacementText(source, identifier, element);
- CompletionSuggestion suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.IDENTIFIER,
- DART_RELEVANCE_HIGH,
- completion,
- identifier.offset,
- 0,
- element.isDeprecated,
- false);
- suggestion.element = protocol.convertElement(element);
- return suggestion;
- }
-
- /**
- * Return a list containing the names of all of the inherited by not
- * implemented members of the class represented by the given [element] that
- * start with the given [prefix]. The [map] is used to find all of the members
- * that are inherited.
- */
- List<String> _computeMemberNames(
- MemberMap map, ClassElement element, String prefix) {
- List<String> memberNames = <String>[];
- int count = map.size;
- for (int i = 0; i < count; i++) {
- String memberName = map.getKey(i);
- if (memberName.startsWith(prefix) && !_hasMember(element, memberName)) {
- memberNames.add(memberName);
- }
- }
- return memberNames;
- }
-
- /**
- * Return `true` if the given [classElement] directly declares a member with
- * the given [memberName].
- */
- bool _hasMember(ClassElement classElement, String memberName) {
- return classElement.getField(memberName) != null ||
- classElement.getGetter(memberName) != null ||
- classElement.getMethod(memberName) != null ||
- classElement.getSetter(memberName) != null;
- }
-
- /**
- * Return `true` if the given [node] looks like a partial identifier inside a
- * class declaration.
- */
- bool _isMemberLevelIdentifier(AstNode node) {
- if (node is SimpleIdentifier) {
- AstNode parent1 = node.parent;
- if (parent1 is TypeName) {
- AstNode parent2 = parent1.parent;
- if (parent2 is VariableDeclarationList) {
- AstNode parent3 = parent2.parent;
- if (parent3 is FieldDeclaration) {
- NodeList<VariableDeclaration> variables = parent2.variables;
- return variables.length == 1 && variables[0].name.name.isEmpty;
- }
- }
- }
- }
- return false;
- }
-
- /**
- * Add any suggestions that are appropriate to the given [request], using the
- * given [element] to find inherited members whose name has the given
- * [identifier] as a prefix.
- */
- List<CompletionSuggestion> _suggestInheritedMembers(
- DartCompletionRequest request,
- SimpleIdentifier identifier,
- ClassElement element) {
- String name = identifier.name;
- InheritanceManager manager = new InheritanceManager(element.library);
- MemberMap map = manager.getMapOfMembersInheritedFromInterfaces(element);
- List<String> memberNames = _computeMemberNames(map, element, name);
- memberNames.sort();
- List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
- for (String memberName in memberNames) {
- CompletionSuggestion suggestion =
- _buildSuggestion(request.source, identifier, map.get(memberName));
- if (suggestion != null) {
- suggestions.add(suggestion);
- }
- }
- return suggestions;
- }
-}
diff --git a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
index 5117855..573dc4b 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -7,99 +7,21 @@
import 'dart:async';
import 'dart:collection';
-import 'package:analysis_server/src/protocol_server.dart' as protocol;
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
+ show createSuggestion;
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart' as engine;
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
-import 'package:path/path.dart' as path;
+
+export 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
+ show createSuggestion;
const String DYNAMIC = 'dynamic';
/**
- * Return a suggestion based upon the given element
- * or `null` if a suggestion is not appropriate for the given element.
- * If the suggestion is not currently in scope, then specify
- * importForSource as the source to which an import should be added.
- */
-CompletionSuggestion createSuggestion(Element element,
- {String completion,
- CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
- int relevance: DART_RELEVANCE_DEFAULT,
- Source importForSource}) {
- if (element is ExecutableElement && element.isOperator) {
- // Do not include operators in suggestions
- return null;
- }
- if (completion == null) {
- completion = element.displayName;
- }
- bool isDeprecated = element.isDeprecated;
- CompletionSuggestion suggestion = new CompletionSuggestion(
- kind,
- isDeprecated ? DART_RELEVANCE_LOW : relevance,
- completion,
- completion.length,
- 0,
- isDeprecated,
- false);
- suggestion.element = protocol.convertElement(element);
- Element enclosingElement = element.enclosingElement;
- if (enclosingElement is ClassElement) {
- suggestion.declaringType = enclosingElement.displayName;
- }
- suggestion.returnType = getReturnTypeString(element);
- if (element is ExecutableElement && element is! PropertyAccessorElement) {
- suggestion.parameterNames = element.parameters
- .map((ParameterElement parameter) => parameter.name)
- .toList();
- suggestion.parameterTypes = element.parameters
- .map((ParameterElement parameter) => parameter.type.displayName)
- .toList();
- suggestion.requiredParameterCount = element.parameters
- .where((ParameterElement parameter) =>
- parameter.parameterKind == ParameterKind.REQUIRED)
- .length;
- suggestion.hasNamedParameters = element.parameters.any(
- (ParameterElement parameter) =>
- parameter.parameterKind == ParameterKind.NAMED);
- }
- if (importForSource != null) {
- String srcPath = path.dirname(importForSource.fullName);
- LibraryElement libElem = element.library;
- if (libElem != null) {
- Source libSource = libElem.source;
- if (libSource != null) {
- UriKind uriKind = libSource.uriKind;
- if (uriKind == UriKind.DART_URI) {
- suggestion.importUri = libSource.uri.toString();
- } else if (uriKind == UriKind.PACKAGE_URI) {
- suggestion.importUri = libSource.uri.toString();
- } else if (uriKind == UriKind.FILE_URI &&
- element.source.uriKind == UriKind.FILE_URI) {
- try {
- suggestion.importUri =
- path.relative(libSource.fullName, from: srcPath);
- } catch (_) {
- // ignored
- }
- }
- }
- }
- if (suggestion.importUri == null) {
- // Do not include out of scope suggestions
- // for which we cannot determine an import
- return null;
- }
- }
- return suggestion;
-}
-
-/**
* Call the given function with each non-null non-empty inherited type name
* that is defined in the given class.
*/
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 45ad25f..f4c51be 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -9,21 +9,28 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'dart:async';
/**
* Compute and return the assists available at the given selection (described by
* the [offset] and [length]) in the given [source]. The source was analyzed in
- * the given [context]. The [plugin] is used to get the list of assist
+ * the given [analysisContext]. The [plugin] is used to get the list of assist
* contributors.
*/
-List<Assist> computeAssists(ServerPlugin plugin, AnalysisContext context,
- Source source, int offset, int length) {
+Future<List<Assist>> computeAssists(
+ ServerPlugin plugin,
+ AnalysisContext analysisContext,
+ Source source,
+ int offset,
+ int length) async {
List<Assist> assists = <Assist>[];
List<AssistContributor> contributors = plugin.assistContributors;
+ AssistContextImpl assistContext =
+ new AssistContextImpl(analysisContext, source, offset, length);
for (AssistContributor contributor in contributors) {
try {
List<Assist> contributedAssists =
- contributor.computeAssists(context, source, offset, length);
+ await contributor.computeAssists(assistContext);
if (contributedAssists != null) {
assists.addAll(contributedAssists);
}
@@ -38,6 +45,26 @@
}
/**
+ * The implementation of [AssistContext].
+ */
+class AssistContextImpl implements AssistContext {
+ @override
+ final AnalysisContext analysisContext;
+
+ @override
+ final Source source;
+
+ @override
+ final int selectionOffset;
+
+ @override
+ final int selectionLength;
+
+ AssistContextImpl(this.analysisContext, this.source, this.selectionOffset,
+ this.selectionLength);
+}
+
+/**
* An enumeration of possible assist kinds.
*/
class DartAssistKind {
@@ -47,6 +74,14 @@
const AssistKind('ADD_TYPE_ANNOTATION', 30, "Add type annotation");
static const ASSIGN_TO_LOCAL_VARIABLE = const AssistKind(
'ASSIGN_TO_LOCAL_VARIABLE', 30, "Assign value to new local variable");
+ static const CONVERT_DOCUMENTATION_INTO_BLOCK = const AssistKind(
+ 'CONVERT_DOCUMENTATION_INTO_BLOCK',
+ 30,
+ "Convert into block documentation comment");
+ static const CONVERT_DOCUMENTATION_INTO_LINE = const AssistKind(
+ 'CONVERT_DOCUMENTATION_INTO_LINE',
+ 30,
+ "Convert into line documentation comment");
static const CONVERT_INTO_BLOCK_BODY = const AssistKind(
'CONVERT_INTO_BLOCK_BODY', 30, "Convert into block body");
static const CONVERT_INTO_EXPRESSION_BODY = const AssistKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index d83ca2f..c6f1c02 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -4,6 +4,7 @@
library services.src.correction.assist;
+import 'dart:async';
import 'dart:collection';
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
@@ -30,38 +31,49 @@
* The computer for Dart assists.
*/
class AssistProcessor {
+ AnalysisContext analysisContext;
+
Source source;
String file;
int fileStamp;
- final CompilationUnit unit;
- final int selectionOffset;
- final int selectionLength;
- AnalysisContext context;
+
+ CompilationUnit unit;
CompilationUnitElement unitElement;
+
LibraryElement unitLibraryElement;
String unitLibraryFile;
String unitLibraryFolder;
+ int selectionOffset;
+ int selectionLength;
+ int selectionEnd;
+
final List<Assist> assists = <Assist>[];
final Map<String, LinkedEditGroup> linkedPositionGroups =
<String, LinkedEditGroup>{};
Position exitPosition = null;
- int selectionEnd;
CorrectionUtils utils;
AstNode node;
SourceChange change = new SourceChange('<message>');
- AssistProcessor(this.unit, this.selectionOffset, this.selectionLength) {
- source = unit.element.source;
- file = source.fullName;
- unitElement = unit.element;
- context = unitElement.context;
- unitLibraryElement = unitElement.library;
+ AssistProcessor(DartAssistContext dartContext) {
+ analysisContext = dartContext.analysisContext;
+ // source
+ source = dartContext.source;
+ file = dartContext.source.fullName;
+ fileStamp = analysisContext.getModificationStamp(source);
+ // unit
+ unit = dartContext.unit;
+ unitElement = dartContext.unit.element;
+ // library
+ unitLibraryElement = dartContext.unit.element.library;
unitLibraryFile = unitLibraryElement.source.fullName;
unitLibraryFolder = dirname(unitLibraryFile);
- fileStamp = unitElement.context.getModificationStamp(source);
+ // selection
+ selectionOffset = dartContext.selectionOffset;
+ selectionLength = dartContext.selectionLength;
selectionEnd = selectionOffset + selectionLength;
}
@@ -70,7 +82,7 @@
*/
String get eol => utils.endOfLine;
- List<Assist> compute() {
+ Future<List<Assist>> compute() async {
utils = new CorrectionUtils(unit);
node = new NodeLocator(selectionOffset, selectionEnd).searchWithin(unit);
if (node == null) {
@@ -81,6 +93,8 @@
_addProposal_addTypeAnnotation_SimpleFormalParameter();
_addProposal_addTypeAnnotation_VariableDeclaration();
_addProposal_assignToLocalVariable();
+ _addProposal_convertDocumentationIntoBlock();
+ _addProposal_convertDocumentationIntoLine();
_addProposal_convertToBlockFunctionBody();
_addProposal_convertToExpressionFunctionBody();
_addProposal_convertToForIndexLoop();
@@ -388,6 +402,80 @@
_addAssist(DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE, []);
}
+ void _addProposal_convertDocumentationIntoBlock() {
+ Comment comment = node.getAncestor((n) => n is Comment);
+ if (comment != null && comment.isDocumentation) {
+ String prefix = utils.getNodePrefix(comment);
+ SourceBuilder sb = new SourceBuilder(file, comment.offset);
+ sb.append('/**');
+ sb.append(eol);
+ for (Token token in comment.tokens) {
+ if (token is DocumentationCommentToken &&
+ token.type == TokenType.SINGLE_LINE_COMMENT) {
+ sb.append(prefix);
+ sb.append(' * ');
+ sb.append(token.lexeme.substring('/// '.length));
+ sb.append(eol);
+ } else {
+ return;
+ }
+ }
+ sb.append(prefix);
+ sb.append(' */');
+ _insertBuilder(sb, comment.length);
+ }
+ // add proposal
+ _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK, []);
+ }
+
+ void _addProposal_convertDocumentationIntoLine() {
+ Comment comment = node.getAncestor((n) => n is Comment);
+ if (comment != null && comment.isDocumentation) {
+ if (comment.tokens.length == 1) {
+ Token token = comment.tokens.first;
+ if (token.type == TokenType.MULTI_LINE_COMMENT) {
+ String text = token.lexeme;
+ List<String> lines = text.split('\n');
+ String prefix = utils.getNodePrefix(comment);
+ SourceBuilder sb = new SourceBuilder(file, comment.offset);
+ bool firstLine = true;
+ String linePrefix = '';
+ for (String line in lines) {
+ if (firstLine) {
+ firstLine = false;
+ String expectedPrefix = '/**';
+ if (!line.startsWith(expectedPrefix)) {
+ return;
+ }
+ line = line.substring(expectedPrefix.length).trim();
+ if (line.isNotEmpty) {
+ sb.append('/// ');
+ sb.append(line);
+ linePrefix = eol + prefix;
+ }
+ } else {
+ if (line.startsWith(prefix + ' */')) {
+ break;
+ }
+ String expectedPrefix = prefix + ' * ';
+ if (!line.startsWith(expectedPrefix)) {
+ return;
+ }
+ line = line.substring(expectedPrefix.length).trim();
+ sb.append(linePrefix);
+ sb.append('/// ');
+ sb.append(line);
+ linePrefix = eol + prefix;
+ }
+ }
+ _insertBuilder(sb, comment.length);
+ }
+ }
+ }
+ // add proposal
+ _addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE, []);
+ }
+
void _addProposal_convertToBlockFunctionBody() {
FunctionBody body = getEnclosingFunctionBody();
// prepare expression body
@@ -579,7 +667,7 @@
// iterable should be List
{
DartType iterableType = iterable.bestType;
- InterfaceType listType = context.typeProvider.listType;
+ InterfaceType listType = analysisContext.typeProvider.listType;
if (iterableType is! InterfaceType ||
iterableType.element != listType.element) {
_coverageMarker();
@@ -811,19 +899,19 @@
void _addProposal_encapsulateField() {
// find FieldDeclaration
- FieldDeclaration fieldDeclaraton =
+ FieldDeclaration fieldDeclaration =
node.getAncestor((x) => x is FieldDeclaration);
- if (fieldDeclaraton == null) {
+ if (fieldDeclaration == null) {
_coverageMarker();
return;
}
// not interesting for static
- if (fieldDeclaraton.isStatic) {
+ if (fieldDeclaration.isStatic) {
_coverageMarker();
return;
}
// has a parse error
- VariableDeclarationList variableList = fieldDeclaraton.fields;
+ VariableDeclarationList variableList = fieldDeclaration.fields;
if (variableList.keyword == null && variableList.type == null) {
_coverageMarker();
return;
@@ -856,7 +944,7 @@
// rename field
_addReplaceEdit(rangeNode(nameNode), '_$name');
// update references in constructors
- ClassDeclaration classDeclaration = fieldDeclaraton.parent;
+ ClassDeclaration classDeclaration = fieldDeclaration.parent;
for (ClassMember member in classDeclaration.members) {
if (member is ConstructorDeclaration) {
for (FormalParameter parameter in member.parameters.parameters) {
@@ -877,7 +965,7 @@
' void set $name(${typeNameCode}$name) {$eol'
' _$name = $name;$eol'
' }';
- _addInsertEdit(fieldDeclaraton.end, getterCode + setterCode);
+ _addInsertEdit(fieldDeclaration.end, getterCode + setterCode);
// add proposal
_addAssist(DartAssistKind.ENCAPSULATE_FIELD, []);
}
@@ -1163,6 +1251,10 @@
// prepare outer "if" statement
AstNode parent = targetIfStatement.parent;
if (parent is Block) {
+ if ((parent as Block).statements.length != 1) {
+ _coverageMarker();
+ return;
+ }
parent = parent.parent;
}
if (parent is! IfStatement) {
@@ -2047,9 +2139,8 @@
*/
class DefaultAssistContributor extends DartAssistContributor {
@override
- List<Assist> internalComputeAssists(
- CompilationUnit unit, int offset, int length) {
- AssistProcessor processor = new AssistProcessor(unit, offset, length);
+ Future<List<Assist>> internalComputeAssists(DartAssistContext context) {
+ AssistProcessor processor = new AssistProcessor(context);
return processor.compute();
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 73f9bd5..a9c4918 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -4,6 +4,8 @@
library analysis_server.src.services.correction.fix;
+import 'dart:async';
+
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analyzer/file_system/file_system.dart';
@@ -17,14 +19,17 @@
* reported after it's source was analyzed in the given [context]. The [plugin]
* is used to get the list of fix contributors.
*/
-List<Fix> computeFixes(ServerPlugin plugin, ResourceProvider resourceProvider,
- AnalysisContext context, AnalysisError error) {
+Future<List<Fix>> computeFixes(
+ ServerPlugin plugin,
+ ResourceProvider resourceProvider,
+ AnalysisContext context,
+ AnalysisError error) async {
List<Fix> fixes = <Fix>[];
List<FixContributor> contributors = plugin.fixContributors;
+ FixContext fixContext = new FixContextImpl(resourceProvider, context, error);
for (FixContributor contributor in contributors) {
try {
- List<Fix> contributedFixes =
- contributor.computeFixes(resourceProvider, context, error);
+ List<Fix> contributedFixes = await contributor.computeFixes(fixContext);
if (contributedFixes != null) {
fixes.addAll(contributedFixes);
}
@@ -122,6 +127,8 @@
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 =
@@ -202,3 +209,24 @@
static const USE_NOT_EQ_NULL =
const FixKind('USE_NOT_EQ_NULL', 50, "Use != null instead of 'is! Null'");
}
+
+/**
+ * The implementation of [FixContext].
+ */
+class FixContextImpl implements FixContext {
+ @override
+ final ResourceProvider resourceProvider;
+
+ @override
+ final AnalysisContext analysisContext;
+
+ @override
+ final AnalysisError error;
+
+ FixContextImpl(this.resourceProvider, this.analysisContext, this.error);
+
+ FixContextImpl.from(FixContext other)
+ : resourceProvider = other.resourceProvider,
+ analysisContext = other.analysisContext,
+ error = other.error;
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index d2c1f86..f068b3b 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -4,6 +4,7 @@
library analysis_server.src.services.correction.fix_internal;
+import 'dart:async';
import 'dart:collection';
import 'dart:core' hide Resource;
@@ -42,13 +43,26 @@
typedef bool ElementPredicate(Element argument);
/**
+ * The implementation of [DartFixContext].
+ *
+ * Clients may not extend, implement or mix-in this class.
+ */
+class DartFixContextImpl extends FixContextImpl implements DartFixContext {
+ /**
+ * The [CompilationUnit] to compute fixes in.
+ */
+ final CompilationUnit unit;
+
+ DartFixContextImpl(FixContext fixContext, this.unit) : super.from(fixContext);
+}
+
+/**
* A [FixContributor] that provides the default set of fixes.
*/
class DefaultFixContributor extends DartFixContributor {
@override
- List<Fix> internalComputeFixes(ResourceProvider resourceProvider,
- CompilationUnit unit, AnalysisError error) {
- FixProcessor processor = new FixProcessor(resourceProvider, unit, error);
+ Future<List<Fix>> internalComputeFixes(DartFixContext context) {
+ FixProcessor processor = new FixProcessor(context);
return processor.compute();
}
}
@@ -59,9 +73,9 @@
class FixProcessor {
static const int MAX_LEVENSHTEIN_DISTANCE = 3;
- final ResourceProvider resourceProvider;
- final CompilationUnit unit;
- final AnalysisError error;
+ ResourceProvider resourceProvider;
+ CompilationUnit unit;
+ AnalysisError error;
AnalysisContext context;
String file;
int fileStamp;
@@ -87,15 +101,22 @@
AstNode node;
AstNode coveredNode;
- FixProcessor(this.resourceProvider, this.unit, this.error) {
+ FixProcessor(DartFixContext dartContext) {
+ resourceProvider = dartContext.resourceProvider;
+ context = dartContext.analysisContext;
+ // unit
+ unit = dartContext.unit;
unitElement = unit.element;
- context = unitElement.context;
unitSource = unitElement.source;
+ // file
file = unitSource.fullName;
fileStamp = context.getModificationStamp(unitSource);
+ // library
unitLibraryElement = unitElement.library;
unitLibraryFile = unitLibraryElement.source.fullName;
unitLibraryFolder = dirname(unitLibraryFile);
+ // error
+ error = dartContext.error;
}
DartType get coreTypeBool => _getCoreType('bool');
@@ -105,15 +126,15 @@
*/
String get eol => utils.endOfLine;
- List<Fix> compute() {
+ Future<List<Fix>> compute() async {
utils = new CorrectionUtils(unit);
errorOffset = error.offset;
errorLength = error.length;
errorEnd = errorOffset + errorLength;
errorRange = new SourceRange(errorOffset, errorLength);
- node = new NodeLocator(errorOffset).searchWithin(unit);
- coveredNode = new NodeLocator(errorOffset, errorOffset + errorLength)
- .searchWithin(unit);
+ node = new NodeLocator2(errorOffset).searchWithin(unit);
+ coveredNode =
+ new NodeLocator2(errorOffset, errorEnd - 1).searchWithin(unit);
// analyze ErrorCode
ErrorCode errorCode = error.errorCode;
if (errorCode == StaticWarningCode.UNDEFINED_CLASS_BOOLEAN) {
@@ -271,6 +292,9 @@
_addFix_useStaticAccess_method();
_addFix_useStaticAccess_property();
}
+ if (errorCode == StaticTypeWarningCode.INVALID_ASSIGNMENT) {
+ _addFix_changeTypeAnnotation();
+ }
if (errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION) {
_addFix_removeParentheses_inGetterInvocation();
}
@@ -359,61 +383,66 @@
}
void _addFix_addMissingParameter() {
- if (node is SimpleIdentifier && node.parent is MethodInvocation) {
+ if (node is ArgumentList && node.parent is MethodInvocation) {
+ ArgumentList argumentList = node;
MethodInvocation invocation = node.parent;
SimpleIdentifier methodName = invocation.methodName;
- ArgumentList argumentList = invocation.argumentList;
- if (methodName == node && argumentList != null) {
- Element targetElement = methodName.bestElement;
- List<Expression> arguments = argumentList.arguments;
- if (targetElement is ExecutableElement) {
- List<ParameterElement> parameters = targetElement.parameters;
- int numParameters = parameters.length;
- Expression argument = arguments[numParameters];
- // prepare target
- int targetOffset;
- if (numParameters != 0) {
- ParameterElement parameterElement = parameters.last;
- AstNode parameterNode = parameterElement.computeNode();
- targetOffset = parameterNode.end;
+ Element targetElement = methodName.bestElement;
+ List<Expression> arguments = argumentList.arguments;
+ if (targetElement is ExecutableElement) {
+ List<ParameterElement> parameters = targetElement.parameters;
+ int numParameters = parameters.length;
+ Iterable<ParameterElement> requiredParameters = parameters
+ .takeWhile((p) => p.parameterKind == ParameterKind.REQUIRED);
+ Iterable<ParameterElement> optionalParameters = parameters
+ .skipWhile((p) => p.parameterKind == ParameterKind.REQUIRED);
+ int numRequired = requiredParameters.length;
+ Expression argument = arguments[numRequired];
+ // prepare target
+ int targetOffset;
+ if (numRequired != 0) {
+ AstNode parameterNode = requiredParameters.last.computeNode();
+ targetOffset = parameterNode.end;
+ } else {
+ AstNode targetNode = targetElement.computeNode();
+ if (targetNode is FunctionDeclaration) {
+ FunctionExpression function = targetNode.functionExpression;
+ targetOffset = function.parameters.leftParenthesis.end;
+ } else if (targetNode is MethodDeclaration) {
+ targetOffset = targetNode.parameters.leftParenthesis.end;
} else {
- AstNode targetNode = targetElement.computeNode();
- if (targetNode is FunctionDeclaration) {
- FunctionExpression function = targetNode.functionExpression;
- targetOffset = function.parameters.leftParenthesis.end;
- } else if (targetNode is MethodDeclaration) {
- targetOffset = targetNode.parameters.leftParenthesis.end;
- } else {
- return;
- }
+ return;
}
- String targetFile = targetElement.source.fullName;
- // required
- {
- SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
- // append source
- if (numParameters != 0) {
- sb.append(', ');
- }
- _appendParameterForArgument(sb, numParameters, argument);
- // add proposal
- _insertBuilder(sb, targetElement);
- _addFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, []);
+ }
+ String targetFile = targetElement.source.fullName;
+ // required
+ {
+ SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
+ // append source
+ if (numRequired != 0) {
+ sb.append(', ');
}
- // optional positional
- {
- SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
- // append source
- if (numParameters != 0) {
- sb.append(', ');
- }
- sb.append('[');
- _appendParameterForArgument(sb, numParameters, argument);
- sb.append(']');
- // add proposal
- _insertBuilder(sb, targetElement);
- _addFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, []);
+ _appendParameterForArgument(sb, numRequired, argument);
+ if (numRequired != numParameters) {
+ sb.append(', ');
}
+ // add proposal
+ _insertBuilder(sb, targetElement);
+ _addFix(DartFixKind.ADD_MISSING_PARAMETER_REQUIRED, []);
+ }
+ // optional positional
+ if (optionalParameters.isEmpty) {
+ SourceBuilder sb = new SourceBuilder(targetFile, targetOffset);
+ // append source
+ if (numRequired != 0) {
+ sb.append(', ');
+ }
+ sb.append('[');
+ _appendParameterForArgument(sb, numRequired, argument);
+ sb.append(']');
+ // add proposal
+ _insertBuilder(sb, targetElement);
+ _addFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL, []);
}
}
}
@@ -467,6 +496,29 @@
}
}
+ 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;
@@ -598,45 +650,26 @@
}
void _addFix_createConstructor_insteadOfSyntheticDefault() {
- TypeName typeName = null;
- ConstructorName constructorName = null;
- InstanceCreationExpression instanceCreation = null;
- if (node is SimpleIdentifier) {
- if (node.parent is TypeName) {
- typeName = node.parent as TypeName;
- if (typeName.name == node && typeName.parent is ConstructorName) {
- constructorName = typeName.parent as ConstructorName;
- // should be synthetic default constructor
- {
- ConstructorElement constructorElement =
- constructorName.staticElement;
- if (constructorElement == null ||
- !constructorElement.isDefaultConstructor ||
- !constructorElement.isSynthetic) {
- return;
- }
- }
- // prepare InstanceCreationExpression
- if (constructorName.parent is InstanceCreationExpression) {
- instanceCreation =
- constructorName.parent as InstanceCreationExpression;
- if (instanceCreation.constructorName != constructorName) {
- return;
- }
- }
- }
- }
+ if (node is! ArgumentList) {
+ return;
}
- // do we have enough information?
- if (instanceCreation == null) {
+ if (node.parent is! InstanceCreationExpression) {
+ return;
+ }
+ InstanceCreationExpression instanceCreation = node.parent;
+ ConstructorName constructorName = instanceCreation.constructorName;
+ // should be synthetic default constructor
+ ConstructorElement constructorElement = constructorName.staticElement;
+ if (constructorElement == null ||
+ !constructorElement.isDefaultConstructor ||
+ !constructorElement.isSynthetic) {
return;
}
// prepare target
- DartType targetType = typeName.type;
- if (targetType is! InterfaceType) {
+ if (constructorElement.enclosingElement is! ClassElement) {
return;
}
- ClassElement targetElement = targetType.element as ClassElement;
+ ClassElement targetElement = constructorElement.enclosingElement;
String targetFile = targetElement.source.fullName;
ClassDeclaration targetClass = getParsedClassElementNode(targetElement);
_ConstructorLocation targetLocation =
@@ -724,6 +757,10 @@
}
void _addFix_createConstructorSuperExplicit() {
+ if (node.parent is! ConstructorDeclaration ||
+ node.parent.parent is! ClassDeclaration) {
+ return;
+ }
ConstructorDeclaration targetConstructor =
node.parent as ConstructorDeclaration;
ClassDeclaration targetClassNode =
@@ -1085,7 +1122,7 @@
Source source = importDirective.source;
if (source != null) {
String file = source.fullName;
- if (isAbsolute(file)) {
+ if (isAbsolute(file) && AnalysisEngine.isDartFileName(file)) {
String libName = _computeLibraryName(file);
SourceEdit edit = new SourceEdit(0, 0, 'library $libName;$eol$eol');
doSourceChange_addSourceEdit(change, context, source, edit);
@@ -1586,11 +1623,12 @@
}
void _addFix_removeParameters_inGetterDeclaration() {
- if (node is SimpleIdentifier && node.parent is MethodDeclaration) {
- MethodDeclaration method = node.parent as MethodDeclaration;
+ if (node is MethodDeclaration) {
+ MethodDeclaration method = node as MethodDeclaration;
+ SimpleIdentifier name = method.name;
FunctionBody body = method.body;
- if (method.name == node && body != null) {
- _addReplaceEdit(rf.rangeEndStart(node, body), ' ');
+ if (name != null && body != null) {
+ _addReplaceEdit(rf.rangeEndStart(name, body), ' ');
_addFix(DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION, []);
}
}
@@ -1951,6 +1989,7 @@
// append parameters
sb.append('(');
List<Expression> arguments = argumentList.arguments;
+ bool hasNamedParameters = false;
for (int i = 0; i < arguments.length; i++) {
Expression argument = arguments[i];
// append separator
@@ -1958,8 +1997,15 @@
sb.append(', ');
}
// append parameter
+ if (argument is NamedExpression && !hasNamedParameters) {
+ hasNamedParameters = true;
+ sb.append('{');
+ }
_appendParameterForArgument(sb, i, argument);
}
+ if (hasNamedParameters) {
+ sb.append('}');
+ }
}
void _addFix_undefinedMethod_useSimilar() {
@@ -2253,7 +2299,9 @@
sb.append(' ');
}
// append parameter name
- {
+ if (argument is NamedExpression) {
+ sb.append(argument.name.label.name);
+ } else {
Set<String> excluded = new Set<String>();
List<String> suggestions =
_getArgumentNameSuggestions(excluded, type, argument, index);
@@ -2354,7 +2402,7 @@
if (relPathParts[0].toLowerCase() == 'lib') {
relPathParts.removeAt(0);
}
- {
+ if (relPathParts.isNotEmpty) {
String nameWithoutExt = pathContext.withoutExtension(relPathParts.last);
relPathParts[relPathParts.length - 1] = nameWithoutExt;
}
diff --git a/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart b/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart
new file mode 100644
index 0000000..a0273ce
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/dependencies/reachable_source_collector.dart
@@ -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));
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 5b2204c..cad43a2 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/index_contributor.dart b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
index 6fcd934..fdcd8fa 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -6,7 +6,7 @@
import 'dart:collection' show Queue;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/correction/namespace.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/index_store.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/index_store.dart b/pkg/analysis_server/lib/src/services/index/index_store.dart
index 574a727..18f80bc 100644
--- a/pkg/analysis_server/lib/src/services/index/index_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_store.dart
@@ -4,7 +4,7 @@
library services.index_store;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_element.dart b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
index 57f8659..df10370 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_element.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
@@ -6,7 +6,7 @@
import 'dart:collection';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_file.dart b/pkg/analysis_server/lib/src/services/index/indexable_file.dart
index 7babfef..4e1c873 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_file.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_file.dart
@@ -4,7 +4,7 @@
library services.index.indexable_file;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analyzer/src/generated/engine.dart';
/**
diff --git a/pkg/analysis_server/lib/src/services/index/local_index.dart b/pkg/analysis_server/lib/src/services/index/local_index.dart
index 624d3ff..115b3e1 100644
--- a/pkg/analysis_server/lib/src/services/index/local_index.dart
+++ b/pkg/analysis_server/lib/src/services/index/local_index.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/store/split_store.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/local_memory_index.dart b/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
index 484085f..ec69627 100644
--- a/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
+++ b/pkg/analysis_server/lib/src/services/index/local_memory_index.dart
@@ -4,7 +4,7 @@
library services.index.memory_file_index;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/index_contributor.dart';
import 'package:analysis_server/src/services/index/local_index.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/store/codec.dart b/pkg/analysis_server/lib/src/services/index/store/codec.dart
index 8fd23ab..9771f56 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -6,7 +6,7 @@
import 'dart:collection';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index 880cad3..85dedd2 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -8,8 +8,8 @@
import 'dart:collection';
import 'dart:typed_data';
-import 'package:analysis_server/plugin/index/index_core.dart';
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/index_store.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
index c865aec..ad42a6e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -197,8 +197,18 @@
AstNode coveringNode = new NodeLocator(
selectionRange.offset, selectionRange.end).searchWithin(unit);
// compute covering expressions
- for (AstNode node = coveringNode; node is Expression; node = node.parent) {
+ for (AstNode node = coveringNode;
+ node is Expression || node is ArgumentList;
+ node = node.parent) {
AstNode parent = node.parent;
+ // skip ArgumentList
+ if (node is ArgumentList) {
+ continue;
+ }
+ // skip AssignmentExpression
+ if (node is AssignmentExpression) {
+ continue;
+ }
// cannot extract the name part of a property access
if (parent is PrefixedIdentifier && parent.identifier == node ||
parent is PropertyAccess && parent.propertyName == node) {
@@ -207,17 +217,15 @@
// fatal selection problems
if (coveringExpressionOffsets.isEmpty) {
if (node is SimpleIdentifier) {
- Element element = node.bestElement;
- if (element is FunctionElement || element is MethodElement) {
- return new RefactoringStatus.fatal(
- 'Cannot extract a single method name.',
- newLocation_fromNode(node));
- }
if (node.inDeclarationContext()) {
return new RefactoringStatus.fatal(
'Cannot extract the name part of a declaration.',
newLocation_fromNode(node));
}
+ Element element = node.bestElement;
+ if (element is FunctionElement || element is MethodElement) {
+ continue;
+ }
}
if (parent is AssignmentExpression && parent.leftHandSide == node) {
return new RefactoringStatus.fatal(
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index cfe43eb..1e89981 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/correction/source_range.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart
index 6cb30db..5488a59 100644
--- a/pkg/analysis_server/lib/src/status/ast_writer.dart
+++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -50,6 +50,9 @@
} 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 @@
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;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 8aa840a..05937c0 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -13,6 +13,7 @@
import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/domain_completion.dart';
+import 'package:analysis_server/src/domain_diagnostic.dart';
import 'package:analysis_server/src/domain_execution.dart';
import 'package:analysis_server/src/operation/operation.dart';
import 'package:analysis_server/src/operation/operation_analysis.dart';
@@ -23,6 +24,7 @@
import 'package:analysis_server/src/socket_server.dart';
import 'package:analysis_server/src/status/ast_writer.dart';
import 'package:analysis_server/src/status/element_writer.dart';
+import 'package:analysis_server/src/utilities/average.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
@@ -30,11 +32,13 @@
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart'
hide AnalysisCache, AnalysisContextImpl, AnalysisTask;
+import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer/src/services/lint.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/src/task/html.dart';
@@ -94,6 +98,11 @@
static const String CONTEXT_PATH = '/context';
/**
+ * The path used to request diagnostic information.
+ */
+ static const String DIAGNOSTIC_PATH = '/diagnostic';
+
+ /**
* The path used to request information about a element model.
*/
static const String ELEMENT_PATH = '/element';
@@ -157,6 +166,11 @@
new ContentType("text", "html", charset: "utf-8");
/**
+ * Rolling average of calls to get diagnostics.
+ */
+ Average _diagnosticCallAverage = new Average();
+
+ /**
* The socket server whose status is to be reported on.
*/
SocketServer _server;
@@ -172,10 +186,22 @@
final Map<String, String> _overlayContents = <String, String>{};
/**
+ * Handler for diagnostics requests.
+ */
+ DiagnosticDomainHandler _diagnosticHandler;
+
+ /**
* Initialize a newly created handler for GET requests.
*/
GetHandler(this._server, this._printBuffer);
+ DiagnosticDomainHandler get diagnosticHandler {
+ if (_diagnosticHandler == null) {
+ _diagnosticHandler = new DiagnosticDomainHandler(_server.analysisServer);
+ }
+ return _diagnosticHandler;
+ }
+
/**
* Return the active [CompletionDomainHandler]
* or `null` if either analysis server is not running
@@ -211,6 +237,8 @@
_returnCommunicationPerformance(request);
} else if (path == CONTEXT_PATH) {
_returnContextInfo(request);
+ } else if (path == DIAGNOSTIC_PATH) {
+ _returnDiagnosticInfo(request);
} else if (path == ELEMENT_PATH) {
_returnElement(request);
} else if (path == INDEX_ELEMENT_BY_NAME) {
@@ -282,6 +310,10 @@
if (unit != null) {
return unit;
}
+ unit = entry.getValue(RESOLVED_UNIT11);
+ if (unit != null) {
+ return unit;
+ }
return entry.getValue(RESOLVED_UNIT);
}
@@ -350,6 +382,7 @@
results.add(RESOLVED_UNIT8);
results.add(RESOLVED_UNIT9);
results.add(RESOLVED_UNIT10);
+ results.add(RESOLVED_UNIT11);
results.add(RESOLVED_UNIT);
results.add(STRONG_MODE_ERRORS);
results.add(USED_IMPORTED_ELEMENTS);
@@ -648,6 +681,7 @@
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);
@@ -664,7 +698,15 @@
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);
+ }
}
}
}
@@ -676,6 +718,11 @@
_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;
@@ -1039,6 +1086,49 @@
?.toList());
}
+ buffer.write('<h3>Configuration</h3>');
+
+ AnalysisOptionsImpl options = context.analysisOptions;
+ buffer.write('<p><b>Options</b></p>');
+ buffer.write('<p>');
+ _writeOption(
+ buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
+ _writeOption(buffer, 'Cache size', options.cacheSize);
+ _writeOption(
+ buffer, 'Enable generic methods', options.enableGenericMethods);
+ _writeOption(buffer, 'Enable strict call checks',
+ options.enableStrictCallChecks);
+ _writeOption(buffer, 'Enable super mixins', options.enableSuperMixins);
+ _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
+ _writeOption(buffer, 'Generate errors in implicit files',
+ options.generateImplicitErrors);
+ _writeOption(
+ buffer, 'Generate errors in SDK files', options.generateSdkErrors);
+ _writeOption(buffer, 'Generate hints', options.hint);
+ _writeOption(buffer, 'Incremental resolution', options.incremental);
+ _writeOption(buffer, 'Incremental resolution with API changes',
+ options.incrementalApi);
+ _writeOption(buffer, 'Preserve comments', options.preserveComments);
+ _writeOption(buffer, 'Strong mode', options.strongMode);
+ _writeOption(buffer, 'Strong mode hints', options.strongModeHints,
+ last: true);
+ buffer.write('</p>');
+
+ List<Linter> lints = context.getConfigurationData(CONFIGURED_LINTS_KEY);
+ buffer.write('<p><b>Lints</b></p>');
+ if (lints.isEmpty) {
+ buffer.write('<p><none></p>');
+ } else {
+ for (Linter lint in lints) {
+ buffer.write('<p> ${lint.runtimeType}</p>');
+ }
+ }
+
+ List<ErrorFilter> errorFilters =
+ context.getConfigurationData(CONFIGURED_ERROR_FILTERS);
+ int filterCount = errorFilters?.length ?? 0;
+ buffer.write('<p><b>Error Filter count</b>: $filterCount</p>');
+
_writeFiles(buffer, 'Priority Files', priorityNames);
_writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
_writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
@@ -1056,6 +1146,20 @@
}
/**
+ * Return a response displaying diagnostic information.
+ */
+ void _returnDiagnosticInfo(HttpRequest request) {
+ String value = request.requestedUri.queryParameters['index'];
+ int index = value != null ? int.parse(value, onError: (_) => 0) : 0;
+ _writeResponse(request, (StringBuffer buffer) {
+ _writePage(buffer, 'Analysis Server - Diagnostic info', [],
+ (StringBuffer buffer) {
+ _writeDiagnosticStatus(buffer);
+ });
+ });
+ }
+
+ /**
* Return a response containing information about an element structure.
*/
void _returnElement(HttpRequest request) {
@@ -1242,6 +1346,9 @@
buffer.write('<p>');
buffer.write(makeLink(OVERLAYS_PATH, {}, 'File overlays'));
buffer.write('</p>');
+ buffer.write('<p>');
+ buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'Diagnostic info'));
+ buffer.write('</p>');
});
});
}
@@ -1307,26 +1414,6 @@
// TODO(brianwilkerson) Add items for the SDK contexts (currently only one).
buffer.write('</p>');
- buffer.write('<p><b>Options</b></p>');
- buffer.write('<p>');
- _writeOption(
- buffer, 'Analyze functon bodies', options.analyzeFunctionBodies);
- _writeOption(buffer, 'Cache size', options.cacheSize);
- _writeOption(
- buffer, 'Enable strict call checks', options.enableStrictCallChecks);
- _writeOption(buffer, 'Enable super mixins', options.enableSuperMixins);
- _writeOption(buffer, 'Generate hints', options.hint);
- _writeOption(buffer, 'Generate dart2js hints', options.dart2jsHint);
- _writeOption(buffer, 'Generate errors in implicit files',
- options.generateImplicitErrors);
- _writeOption(
- buffer, 'Generate errors in SDK files', options.generateSdkErrors);
- _writeOption(buffer, 'Incremental resolution', options.incremental);
- _writeOption(buffer, 'Incremental resolution with API changes',
- options.incrementalApi);
- _writeOption(buffer, 'Preserve comments', options.preserveComments,
- last: true);
- buffer.write('</p>');
int freq = AnalysisServer.performOperationDelayFreqency;
String delay = freq > 0 ? '1 ms every $freq ms' : 'off';
buffer.write('<p><b>perform operation delay:</b> $delay</p>');
@@ -1444,6 +1531,47 @@
}
/**
+ * Write the status of the diagnostic domain to the given [buffer].
+ */
+ void _writeDiagnosticStatus(StringBuffer buffer) {
+ var request = new DiagnosticGetDiagnosticsParams().toRequest('0');
+
+ var stopwatch = new Stopwatch();
+ stopwatch.start();
+ var response = diagnosticHandler.handleRequest(request);
+ stopwatch.stop();
+
+ int elapsedMs = stopwatch.elapsedMilliseconds;
+ _diagnosticCallAverage.addSample(elapsedMs);
+
+ buffer.write('<h3>Timing</h3>');
+
+ buffer.write('<p>');
+ buffer.write('getDiagnostic (last call): $elapsedMs (ms)');
+ buffer.write('<p>');
+ buffer.write('getDiagnostic (rolling average): '
+ '${_diagnosticCallAverage.value} (ms)');
+ buffer.write('<p> ');
+
+ var json = response.toJson()[Response.RESULT];
+ List contexts = json['contexts'];
+ for (var context in contexts) {
+ buffer.write('<p>');
+ buffer.write('<h3>${context["name"]}</h3>');
+ buffer.write('<p>');
+ buffer.write('explicitFileCount: ${context["explicitFileCount"]}');
+ buffer.write('<p>');
+ buffer.write('implicitFileCount: ${context["implicitFileCount"]}');
+ buffer.write('<p>');
+ buffer.write('workItemQueueLength: ${context["workItemQueueLength"]}');
+ buffer.write('<p>');
+ buffer.write('workItemQueueLengthAverage: '
+ '${context["workItemQueueLengthAverage"]}');
+ buffer.write('<p> ');
+ }
+ }
+
+ /**
* Write the status of the edit domain (on the main status page) to the given
* [buffer].
*/
diff --git a/pkg/analysis_server/lib/src/utilities/average.dart b/pkg/analysis_server/lib/src/utilities/average.dart
new file mode 100644
index 0000000..a738d39
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/average.dart
@@ -0,0 +1,30 @@
+// 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 analysis_server.src.utilities.average;
+
+/// Simple rolling average sample counter.
+class Average {
+ num _val;
+ final int _sampleCount;
+
+ /// Create an average with the given (optional) sample count size.
+ Average([this._sampleCount = 20]);
+
+ /// The current average.
+ num get value => _val ?? 0;
+
+ /// Add the given [sample].
+ void addSample(num sample) {
+ if (_val == null) {
+ _val = sample;
+ } else {
+ _val = _val * ((_sampleCount - 1) / _sampleCount) +
+ sample * (1 / _sampleCount);
+ }
+ }
+
+ @override
+ String toString() => 'average: ${value}';
+}
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
index a5fe204..cb103f8 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_core.dart
@@ -4,8 +4,8 @@
library analysis_server.src.utilities.change_builder_core;
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
import 'package:analyzer/src/generated/source.dart';
/**
diff --git a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
index f40dd36..56fc80f 100644
--- a/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
+++ b/pkg/analysis_server/lib/src/utilities/change_builder_dart.dart
@@ -4,9 +4,9 @@
library analysis_server.src.utilities.change_builder_dart;
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart' hide ElementKind;
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_dart.dart';
import 'package:analysis_server/src/services/correction/name_suggestion.dart';
import 'package:analysis_server/src/services/correction/util.dart';
import 'package:analysis_server/src/utilities/change_builder_core.dart';
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 951b5b4..d800ed4 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
environment:
sdk: '>=1.12.0 <2.0.0'
dependencies:
- analyzer: '>=0.26.2+1 <0.27.0'
+ analyzer: '>=0.26.3 <0.27.0'
args: '>=0.13.0 <0.14.0'
dart_style: '>=0.2.0 <0.3.0'
linter: ^0.1.3+2
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 46f0dbf..8049890 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -10,6 +10,7 @@
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/java_engine.dart' show CaughtException;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source_io.dart';
@@ -91,6 +92,7 @@
context = AnalysisEngine.instance.createAnalysisContext();
context.sourceFactory =
new SourceFactory([SDK_RESOLVER, packageResolver, resourceResolver]);
+ AnalysisEngine.instance.logger = PrintLogger.instance;
}
void setupResourceProvider() {
@@ -100,6 +102,46 @@
void tearDown() {
context = null;
provider = null;
+ AnalysisEngine.instance.logger = null;
+ }
+}
+
+/**
+ * Instances of the class [PrintLogger] print all of the errors.
+ */
+class PrintLogger implements Logger {
+ static final Logger instance = new PrintLogger();
+
+ @override
+ void logError(String message, [CaughtException exception]) {
+ print(message);
+ if (exception != null) {
+ print(exception);
+ }
+ }
+
+ @override
+ void logError2(String message, Object exception) {
+ print(message);
+ if (exception != null) {
+ print(exception);
+ }
+ }
+
+ @override
+ void logInformation(String message, [CaughtException exception]) {
+ print(message);
+ if (exception != null) {
+ print(exception);
+ }
+ }
+
+ @override
+ void logInformation2(String message, Object exception) {
+ print(message);
+ if (exception != null) {
+ print(exception);
+ }
}
}
diff --git a/pkg/analysis_server/test/analysis/get_errors_test.dart b/pkg/analysis_server/test/analysis/get_errors_test.dart
index 205cbbe..a665cfa 100644
--- a/pkg/analysis_server/test/analysis/get_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/get_errors_test.dart
@@ -30,17 +30,42 @@
createProject();
}
- test_afterAnalysisComplete() {
+ test_afterAnalysisComplete() async {
addTestFile('''
main() {
print(42)
}
''');
- return waitForTasksFinished().then((_) {
- return _getErrors(testFile).then((List<AnalysisError> errors) {
- expect(errors, hasLength(1));
- });
- });
+ await waitForTasksFinished();
+ List<AnalysisError> errors = await _getErrors(testFile);
+ expect(errors, hasLength(1));
+ }
+
+ test_errorInPart() async {
+ String libPath = '$testFolder/main.dart';
+ String partPath = '$testFolder/main_part.dart';
+ addFile(
+ libPath,
+ r'''
+library main;
+part 'main_part.dart';
+class A {}
+''');
+ addFile(
+ partPath,
+ r'''
+part of main;
+class A {}
+''');
+ await waitForTasksFinished();
+ {
+ List<AnalysisError> libErrors = await _getErrors(libPath);
+ expect(libErrors, isEmpty);
+ }
+ {
+ List<AnalysisError> partErrors = await _getErrors(partPath);
+ expect(partErrors, hasLength(1));
+ }
}
test_fileDoesNotExist() {
@@ -60,69 +85,64 @@
return _checkInvalid(file);
}
- test_hasErrors() {
+ test_hasErrors() async {
addTestFile('''
main() {
print(42)
}
''');
- return _getErrors(testFile).then((List<AnalysisError> errors) {
- expect(errors, hasLength(1));
- {
- AnalysisError error = errors[0];
- expect(error.severity, AnalysisErrorSeverity.ERROR);
- expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
- expect(error.location.file, testFile);
- expect(error.location.startLine, 2);
- }
- });
+ List<AnalysisError> errors = await _getErrors(testFile);
+ expect(errors, hasLength(1));
+ {
+ AnalysisError error = errors[0];
+ expect(error.severity, AnalysisErrorSeverity.ERROR);
+ expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
+ expect(error.location.file, testFile);
+ expect(error.location.startLine, 2);
+ }
}
- test_noErrors() {
+ test_noErrors() async {
addTestFile('''
main() {
print(42);
}
''');
- return _getErrors(testFile).then((List<AnalysisError> errors) {
- expect(errors, isEmpty);
- });
+ List<AnalysisError> errors = await _getErrors(testFile);
+ expect(errors, isEmpty);
}
- test_removeContextAfterRequest() {
+ test_removeContextAfterRequest() async {
addTestFile('''
main() {
print(42)
}
''');
// handle the request synchronously
- Request request = _createGetErrorsRequest();
+ Request request = _createGetErrorsRequest(testFile);
server.handleRequest(request);
// remove context, causes sending an "invalid file" error
resourceProvider.deleteFolder(projectPath);
// wait for an error response
- return serverChannel.waitForResponse(request).then((Response response) {
- expect(response.error, isNotNull);
- expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
- });
+ Response response = await serverChannel.waitForResponse(request);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
}
- Future _checkInvalid(String file) {
- Request request = _createGetErrorsRequest();
- return serverChannel.sendRequest(request).then((Response response) {
- expect(response.error, isNotNull);
- expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
- });
+ Future _checkInvalid(String file) async {
+ Request request = _createGetErrorsRequest(file);
+ Response response = await serverChannel.sendRequest(request);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.GET_ERRORS_INVALID_FILE);
}
- Request _createGetErrorsRequest() {
- return new AnalysisGetErrorsParams(testFile).toRequest(requestId);
+ Request _createGetErrorsRequest(String file) {
+ return new AnalysisGetErrorsParams(file).toRequest(requestId);
}
- Future<List<AnalysisError>> _getErrors(String file) {
- Request request = _createGetErrorsRequest();
- return serverChannel.sendRequest(request).then((Response response) {
- return new AnalysisGetErrorsResult.fromResponse(response).errors;
- });
+ Future<List<AnalysisError>> _getErrors(String file) async {
+ Request request = _createGetErrorsRequest(file);
+ Response response = await serverChannel.sendRequest(request);
+ return new AnalysisGetErrorsResult.fromResponse(response).errors;
}
}
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index 34db510..cc5befe 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -25,15 +25,14 @@
return prepareHoverAt(offset);
}
- Future<HoverInformation> prepareHoverAt(int offset) {
- return waitForTasksFinished().then((_) {
- Request request =
- new AnalysisGetHoverParams(testFile, offset).toRequest('0');
- Response response = handleSuccessfulRequest(request);
- var result = new AnalysisGetHoverResult.fromResponse(response);
- List<HoverInformation> hovers = result.hovers;
- return hovers.isNotEmpty ? hovers.first : null;
- });
+ Future<HoverInformation> prepareHoverAt(int offset) async {
+ await waitForTasksFinished();
+ Request request =
+ new AnalysisGetHoverParams(testFile, offset).toRequest('0');
+ Response response = handleSuccessfulRequest(request);
+ var result = new AnalysisGetHoverResult.fromResponse(response);
+ List<HoverInformation> hovers = result.hovers;
+ return hovers.isNotEmpty ? hovers.first : null;
}
@override
@@ -42,7 +41,7 @@
createProject();
}
- test_dartdoc_clunky() {
+ test_dartdoc_clunky() async {
addTestFile('''
library my.library;
/**
@@ -52,12 +51,11 @@
main() {
}
''');
- return prepareHover('main() {').then((HoverInformation hover) {
- expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- });
+ HoverInformation hover = await prepareHover('main() {');
+ expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
}
- test_dartdoc_elegant() {
+ test_dartdoc_elegant() async {
addTestFile('''
library my.library;
/// doc aaa
@@ -65,12 +63,11 @@
main() {
}
''');
- return prepareHover('main() {').then((HoverInformation hover) {
- expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- });
+ HoverInformation hover = await prepareHover('main() {');
+ expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
}
- test_expression_function() {
+ test_expression_function() async {
addTestFile('''
library my.library;
/// doc aaa
@@ -78,43 +75,41 @@
List<String> fff(int a, String b) {
}
''');
- return prepareHover('fff(int a').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
- expect(hover.containingClassDescription, isNull);
- expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- expect(hover.elementDescription, 'fff(int a, String b) → List<String>');
- expect(hover.elementKind, 'function');
- // types
- expect(hover.staticType, '(int, String) → List<String>');
- expect(hover.propagatedType, isNull);
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('fff(int a');
+ // element
+ expect(hover.containingLibraryName, 'my.library');
+ expect(hover.containingLibraryPath, testFile);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+ expect(hover.elementDescription, 'fff(int a, String b) → List<String>');
+ expect(hover.elementKind, 'function');
+ // types
+ expect(hover.staticType, '(int, String) → List<String>');
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_expression_literal_noElement() {
+ test_expression_literal_noElement() async {
addTestFile('''
main() {
foo(123);
}
foo(Object myParameter) {}
''');
- return prepareHover('123').then((HoverInformation hover) {
- // literal, no Element
- expect(hover.containingClassDescription, isNull);
- expect(hover.elementDescription, isNull);
- expect(hover.elementKind, isNull);
- // types
- expect(hover.staticType, 'int');
- expect(hover.propagatedType, isNull);
- // parameter
- expect(hover.parameter, 'Object myParameter');
- });
+ HoverInformation hover = await prepareHover('123');
+ // literal, no Element
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.elementDescription, isNull);
+ expect(hover.elementKind, isNull);
+ // types
+ expect(hover.staticType, 'int');
+ expect(hover.propagatedType, isNull);
+ // parameter
+ expect(hover.parameter, 'Object myParameter');
}
- test_expression_method() {
+ test_expression_method() async {
addTestFile('''
library my.library;
class A {
@@ -124,23 +119,22 @@
}
}
''');
- return prepareHover('mmm(int a').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
- expect(hover.containingClassDescription, 'A');
- expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
- expect(hover.elementKind, 'method');
- // types
- expect(hover.staticType, '(int, String) → List<String>');
- expect(hover.propagatedType, isNull);
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('mmm(int a');
+ // element
+ expect(hover.containingLibraryName, 'my.library');
+ expect(hover.containingLibraryPath, testFile);
+ expect(hover.containingClassDescription, 'A');
+ expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+ expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
+ expect(hover.elementKind, 'method');
+ // types
+ expect(hover.staticType, '(int, String) → List<String>');
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_expression_method_invocation() {
+ test_expression_method_invocation() async {
addTestFile('''
library my.library;
class A {
@@ -151,24 +145,23 @@
a.mmm(42, 'foo');
}
''');
- return prepareHover('mm(42, ').then((HoverInformation hover) {
- // range
- expect(hover.offset, findOffset('mmm(42, '));
- expect(hover.length, 'mmm'.length);
- // element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
- expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
- expect(hover.elementKind, 'method');
- // types
- expect(hover.staticType, isNull);
- expect(hover.propagatedType, isNull);
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('mm(42, ');
+ // range
+ expect(hover.offset, findOffset('mmm(42, '));
+ expect(hover.length, 'mmm'.length);
+ // element
+ expect(hover.containingLibraryName, 'my.library');
+ expect(hover.containingLibraryPath, testFile);
+ expect(hover.elementDescription, 'mmm(int a, String b) → List<String>');
+ expect(hover.elementKind, 'method');
+ // types
+ expect(hover.staticType, isNull);
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_expression_parameter() {
+ test_expression_parameter() async {
addTestFile('''
library my.library;
class A {
@@ -177,23 +170,22 @@
}
}
''');
- return prepareHover('p) {').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, isNull);
- expect(hover.containingLibraryPath, isNull);
- expect(hover.containingClassDescription, isNull);
- expect(hover.dartdoc, 'The method documentation.');
- expect(hover.elementDescription, 'int p');
- expect(hover.elementKind, 'parameter');
- // types
- expect(hover.staticType, 'int');
- expect(hover.propagatedType, isNull);
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('p) {');
+ // element
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, 'The method documentation.');
+ expect(hover.elementDescription, 'int p');
+ expect(hover.elementKind, 'parameter');
+ // types
+ expect(hover.staticType, 'int');
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_expression_syntheticGetter() {
+ test_expression_syntheticGetter() async {
addTestFile('''
library my.library;
class A {
@@ -205,21 +197,20 @@
print(a.fff);
}
''');
- return prepareHover('fff);').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
- expect(hover.containingClassDescription, 'A');
- expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
- expect(hover.elementDescription, 'String fff');
- expect(hover.elementKind, 'field');
- // types
- expect(hover.staticType, 'String');
- expect(hover.propagatedType, isNull);
- });
+ HoverInformation hover = await prepareHover('fff);');
+ // element
+ expect(hover.containingLibraryName, 'my.library');
+ expect(hover.containingLibraryPath, testFile);
+ expect(hover.containingClassDescription, 'A');
+ expect(hover.dartdoc, '''doc aaa\ndoc bbb''');
+ expect(hover.elementDescription, 'String fff');
+ expect(hover.elementKind, 'field');
+ // types
+ expect(hover.staticType, 'String');
+ expect(hover.propagatedType, isNull);
}
- test_expression_variable_hasPropagatedType() {
+ test_expression_variable_hasPropagatedType() async {
addTestFile('''
library my.library;
main() {
@@ -227,21 +218,20 @@
print(vvv);
}
''');
- return prepareHover('vvv);').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, isNull);
- expect(hover.containingLibraryPath, isNull);
- expect(hover.containingClassDescription, isNull);
- expect(hover.dartdoc, isNull);
- expect(hover.elementDescription, 'dynamic vvv');
- expect(hover.elementKind, 'local variable');
- // types
- expect(hover.staticType, 'dynamic');
- expect(hover.propagatedType, 'int');
- });
+ HoverInformation hover = await prepareHover('vvv);');
+ // element
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, isNull);
+ expect(hover.elementDescription, 'dynamic vvv');
+ expect(hover.elementKind, 'local variable');
+ // types
+ expect(hover.staticType, 'dynamic');
+ expect(hover.propagatedType, 'int');
}
- test_expression_variable_inMethod() {
+ test_expression_variable_inMethod() async {
addTestFile('''
library my.library;
class A {
@@ -250,23 +240,22 @@
}
}
''');
- return prepareHover('vvv = 42').then((HoverInformation hover) {
- // element
- expect(hover.containingLibraryName, isNull);
- expect(hover.containingLibraryPath, isNull);
- expect(hover.containingClassDescription, isNull);
- expect(hover.dartdoc, isNull);
- expect(hover.elementDescription, 'num vvv');
- expect(hover.elementKind, 'local variable');
- // types
- expect(hover.staticType, 'num');
- expect(hover.propagatedType, 'int');
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('vvv = 42');
+ // element
+ expect(hover.containingLibraryName, isNull);
+ expect(hover.containingLibraryPath, isNull);
+ expect(hover.containingClassDescription, isNull);
+ expect(hover.dartdoc, isNull);
+ expect(hover.elementDescription, 'num vvv');
+ expect(hover.elementKind, 'local variable');
+ // types
+ expect(hover.staticType, 'num');
+ expect(hover.propagatedType, 'int');
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_instanceCreation_implicit() {
+ test_instanceCreation_implicit() async {
addTestFile('''
library my.library;
class A {
@@ -275,25 +264,24 @@
new A();
}
''');
- return prepareHover('new A').then((HoverInformation hover) {
- // range
- expect(hover.offset, findOffset('new A'));
- expect(hover.length, 'new A()'.length);
- // element
- expect(hover.containingLibraryName, 'my.library');
- expect(hover.containingLibraryPath, testFile);
- expect(hover.dartdoc, isNull);
- expect(hover.elementDescription, 'A() → A');
- expect(hover.elementKind, 'constructor');
- // types
- expect(hover.staticType, 'A');
- expect(hover.propagatedType, isNull);
- // no parameter
- expect(hover.parameter, isNull);
- });
+ HoverInformation hover = await prepareHover('new A');
+ // range
+ expect(hover.offset, findOffset('new A'));
+ expect(hover.length, 'new A()'.length);
+ // element
+ expect(hover.containingLibraryName, 'my.library');
+ expect(hover.containingLibraryPath, testFile);
+ expect(hover.dartdoc, isNull);
+ expect(hover.elementDescription, 'A() → A');
+ expect(hover.elementKind, 'constructor');
+ // types
+ expect(hover.staticType, 'A');
+ expect(hover.propagatedType, isNull);
+ // no parameter
+ expect(hover.parameter, isNull);
}
- test_instanceCreation_implicit_withTypeArgument() {
+ test_instanceCreation_implicit_withTypeArgument() async {
addTestFile('''
library my.library;
class A<T> {}
@@ -301,7 +289,7 @@
new A<String>();
}
''');
- Function onConstructor = (HoverInformation hover) {
+ void onConstructor(HoverInformation hover) {
// range
expect(hover.offset, findOffset('new A<String>'));
expect(hover.length, 'new A<String>()'.length);
@@ -316,18 +304,24 @@
expect(hover.propagatedType, isNull);
// no parameter
expect(hover.parameter, isNull);
- };
- var futureNewA = prepareHover('new A').then(onConstructor);
- var futureA = prepareHover('A<String>()').then(onConstructor);
- var futureString = prepareHover('String>').then((HoverInformation hover) {
+ }
+ {
+ HoverInformation hover = await prepareHover('new A');
+ onConstructor(hover);
+ }
+ {
+ HoverInformation hover = await prepareHover('A<String>()');
+ onConstructor(hover);
+ }
+ {
+ HoverInformation hover = await prepareHover('String>');
expect(hover.offset, findOffset('String>'));
expect(hover.length, 'String'.length);
expect(hover.elementKind, 'class');
- });
- return Future.wait([futureNewA, futureA, futureString]);
+ }
}
- test_instanceCreation_named() {
+ test_instanceCreation_named() async {
addTestFile('''
library my.library;
class A {
@@ -338,7 +332,7 @@
new A.named();
}
''');
- var onConstructor = (HoverInformation hover) {
+ void onConstructor(HoverInformation hover) {
// range
expect(hover.offset, findOffset('new A'));
expect(hover.length, 'new A.named()'.length);
@@ -346,21 +340,25 @@
expect(hover.dartdoc, 'my doc');
expect(hover.elementDescription, 'A.named() → A');
expect(hover.elementKind, 'constructor');
- };
- var futureCreation = prepareHover('new A').then(onConstructor);
- var futureName = prepareHover('named();').then(onConstructor);
- return Future.wait([futureCreation, futureName]);
+ }
+ {
+ HoverInformation hover = await prepareHover('new A');
+ onConstructor(hover);
+ }
+ {
+ HoverInformation hover = await prepareHover('named();');
+ onConstructor(hover);
+ }
}
- test_noHoverInfo() {
+ test_noHoverInfo() async {
addTestFile('''
library my.library;
main() {
// nothing
}
''');
- return prepareHover('nothing').then((HoverInformation hover) {
- expect(hover, isNull);
- });
+ HoverInformation hover = await prepareHover('nothing');
+ expect(hover, isNull);
}
}
diff --git a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
index 13c5073..0ce9e164 100644
--- a/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analyzedFiles_test.dart
@@ -49,24 +49,21 @@
createProject();
}
- test_afterAnalysis() {
+ test_afterAnalysis() async {
addTestFile('''
class A {}
''');
- return waitForTasksFinished().then((_) {
- return prepareAnalyzedFiles().then((_) {
- assertHasFile(testFile);
- });
- });
+ await waitForTasksFinished();
+ await prepareAnalyzedFiles();
+ assertHasFile(testFile);
}
- test_beforeAnalysis() {
+ test_beforeAnalysis() async {
addTestFile('''
class A {}
''');
- return prepareAnalyzedFiles().then((_) {
- assertHasFile(testFile);
- });
+ await prepareAnalyzedFiles();
+ assertHasFile(testFile);
}
test_insignificant_change() async {
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index 46de68d..dbbe7af 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -48,25 +48,24 @@
super.tearDown();
}
- test_importError() {
+ test_importError() async {
createProject();
addTestFile('''
import 'does_not_exist.dart';
''');
- return waitForTasksFinished().then((_) {
- List<AnalysisError> errors = filesErrors[testFile];
- // Verify that we are generating only 1 error for the bad URI.
- // https://github.com/dart-lang/sdk/issues/23754
- expect(errors, hasLength(1));
- AnalysisError error = errors[0];
- expect(error.severity, AnalysisErrorSeverity.ERROR);
- expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
- expect(error.message, startsWith('Target of URI does not exist'));
- });
+ await waitForTasksFinished();
+ List<AnalysisError> errors = filesErrors[testFile];
+ // Verify that we are generating only 1 error for the bad URI.
+ // https://github.com/dart-lang/sdk/issues/23754
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.severity, AnalysisErrorSeverity.ERROR);
+ expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
+ expect(error.message, startsWith('Target of URI does not exist'));
}
- test_lintError() {
+ test_lintError() async {
// Requires task model.
AnalysisEngine.instance.useTaskModel = true;
@@ -86,69 +85,64 @@
new AnalysisSetAnalysisRootsParams([projectPath], []).toRequest('0');
handleSuccessfulRequest(request);
- return waitForTasksFinished().then((_) {
- AnalysisContext testContext = server.getContainingContext(testFile);
- List<Linter> lints = getLints(testContext);
- // Registry should only contain single lint rule.
- expect(lints, hasLength(1));
- LintRule lint = lints.first as LintRule;
- expect(lint.name, camelCaseTypesLintName);
- // Verify lint error result.
- List<AnalysisError> errors = filesErrors[testFile];
- expect(errors, hasLength(1));
- AnalysisError error = errors[0];
- expect(error.location.file, '/project/bin/test.dart');
- expect(error.severity, AnalysisErrorSeverity.INFO);
- expect(error.type, AnalysisErrorType.LINT);
- expect(error.message, lint.description);
- });
+ await waitForTasksFinished();
+ AnalysisContext testContext = server.getContainingContext(testFile);
+ List<Linter> lints = getLints(testContext);
+ // Registry should only contain single lint rule.
+ expect(lints, hasLength(1));
+ LintRule lint = lints.first as LintRule;
+ expect(lint.name, camelCaseTypesLintName);
+ // Verify lint error result.
+ List<AnalysisError> errors = filesErrors[testFile];
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.location.file, '/project/bin/test.dart');
+ expect(error.severity, AnalysisErrorSeverity.INFO);
+ expect(error.type, AnalysisErrorType.LINT);
+ expect(error.message, lint.description);
}
- test_notInAnalysisRoot() {
+ test_notInAnalysisRoot() async {
createProject();
String otherFile = '/other.dart';
addFile(otherFile, 'UnknownType V;');
addTestFile('''
import '/other.dart';
-
main() {
print(V);
}
''');
- return waitForTasksFinished().then((_) {
- expect(filesErrors[otherFile], isNull);
- });
+ await waitForTasksFinished();
+ expect(filesErrors[otherFile], isNull);
}
- test_ParserError() {
+ test_ParserError() async {
createProject();
addTestFile('library lib');
- return waitForTasksFinished().then((_) {
- List<AnalysisError> errors = filesErrors[testFile];
- expect(errors, hasLength(1));
- AnalysisError error = errors[0];
- expect(error.location.file, '/project/bin/test.dart');
- expect(error.location.offset, isPositive);
- expect(error.location.length, isNonNegative);
- expect(error.severity, AnalysisErrorSeverity.ERROR);
- expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
- expect(error.message, isNotNull);
- });
+ await waitForTasksFinished();
+ List<AnalysisError> errors = filesErrors[testFile];
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.location.file, '/project/bin/test.dart');
+ expect(error.location.offset, isPositive);
+ expect(error.location.length, isNonNegative);
+ expect(error.severity, AnalysisErrorSeverity.ERROR);
+ expect(error.type, AnalysisErrorType.SYNTACTIC_ERROR);
+ expect(error.message, isNotNull);
}
- test_StaticWarning() {
+ test_StaticWarning() async {
createProject();
addTestFile('''
main() {
print(UNKNOWN);
}
''');
- return waitForTasksFinished().then((_) {
- List<AnalysisError> errors = filesErrors[testFile];
- expect(errors, hasLength(1));
- AnalysisError error = errors[0];
- expect(error.severity, AnalysisErrorSeverity.WARNING);
- expect(error.type, AnalysisErrorType.STATIC_WARNING);
- });
+ await waitForTasksFinished();
+ List<AnalysisError> errors = filesErrors[testFile];
+ expect(errors, hasLength(1));
+ AnalysisError error = errors[0];
+ expect(error.severity, AnalysisErrorSeverity.WARNING);
+ expect(error.type, AnalysisErrorType.STATIC_WARNING);
}
}
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test.dart b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
index a44d798..6c2b57a3 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test.dart
@@ -108,58 +108,54 @@
createProject();
}
- test_ANNOTATION_hasArguments() {
+ test_ANNOTATION_hasArguments() async {
addTestFile('''
class AAA {
const AAA(a, b, c);
}
@AAA(1, 2, 3) main() {}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
- assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
+ assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
}
- test_ANNOTATION_noArguments() {
+ test_ANNOTATION_noArguments() async {
addTestFile('''
const AAA = 42;
@AAA main() {}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
}
- test_BUILT_IN_abstract() {
+ test_BUILT_IN_abstract() async {
addTestFile('''
abstract class A {};
abstract class B = Object with A;
main() {
var abstract = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
}
- test_BUILT_IN_as() {
+ test_BUILT_IN_as() async {
addTestFile('''
import 'dart:math' as math;
main() {
p as int;
var as = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
}
- test_BUILT_IN_async() {
+ test_BUILT_IN_async() async {
addTestFile('''
fa() async {}
fb() async* {}
@@ -167,14 +163,13 @@
bool async = false;
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
}
- test_BUILT_IN_await() {
+ test_BUILT_IN_await() async {
addTestFile('''
main() async {
await 42;
@@ -183,37 +178,34 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
}
- test_BUILT_IN_deferred() {
+ test_BUILT_IN_deferred() async {
addTestFile('''
import 'dart:math' deferred as math;
main() {
var deferred = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
}
- test_BUILT_IN_export() {
+ test_BUILT_IN_export() async {
addTestFile('''
export "dart:math";
main() {
var export = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
}
- test_BUILT_IN_external() {
+ test_BUILT_IN_external() async {
addTestFile('''
class A {
external A();
@@ -222,15 +214,14 @@
external main() {
var external = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
}
- test_BUILT_IN_factory() {
+ test_BUILT_IN_factory() async {
addTestFile('''
class A {
factory A() => null;
@@ -238,13 +229,12 @@
main() {
var factory = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
}
- test_BUILT_IN_get() {
+ test_BUILT_IN_get() async {
addTestFile('''
get aaa => 1;
class A {
@@ -253,63 +243,58 @@
main() {
var get = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
}
- test_BUILT_IN_hide() {
+ test_BUILT_IN_hide() async {
addTestFile('''
import 'foo.dart' hide Foo;
main() {
var hide = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
}
- test_BUILT_IN_implements() {
+ test_BUILT_IN_implements() async {
addTestFile('''
class A {}
class B implements A {}
main() {
var implements = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
}
- test_BUILT_IN_import() {
+ test_BUILT_IN_import() async {
addTestFile('''
import "foo.dart";
main() {
var import = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
}
- test_BUILT_IN_library() {
+ test_BUILT_IN_library() async {
addTestFile('''
library lib;
main() {
var library = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
}
- test_BUILT_IN_native() {
+ test_BUILT_IN_native() async {
addTestFile('''
class A native "A_native" {}
class B {
@@ -318,14 +303,13 @@
main() {
var native = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
}
- test_BUILT_IN_on() {
+ test_BUILT_IN_on() async {
addTestFile('''
main() {
try {
@@ -333,13 +317,12 @@
}
var on = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
}
- test_BUILT_IN_operator() {
+ test_BUILT_IN_operator() async {
addTestFile('''
class A {
operator +(x) => null;
@@ -347,26 +330,24 @@
main() {
var operator = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
}
- test_BUILT_IN_part() {
+ test_BUILT_IN_part() async {
addTestFile('''
part "my_part.dart";
main() {
var part = 42;
}''');
addFile('/project/bin/my_part.dart', 'part of lib;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
}
- test_BUILT_IN_partOf() {
+ test_BUILT_IN_partOf() async {
addTestFile('''
part of lib;
main() {
@@ -374,15 +355,13 @@
var of = 2;
}''');
_addLibraryForTestPart();
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
- assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
}
- test_BUILT_IN_set() {
+ test_BUILT_IN_set() async {
addTestFile('''
set aaa(x) {}
class A
@@ -391,26 +370,24 @@
main() {
var set = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
}
- test_BUILT_IN_show() {
+ test_BUILT_IN_show() async {
addTestFile('''
import 'foo.dart' show Foo;
main() {
var show = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
}
- test_BUILT_IN_static() {
+ test_BUILT_IN_static() async {
addTestFile('''
class A {
static aaa;
@@ -419,14 +396,13 @@
main() {
var static = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
}
- test_BUILT_IN_sync() {
+ test_BUILT_IN_sync() async {
addTestFile('''
fa() sync {}
fb() sync* {}
@@ -434,81 +410,74 @@
bool sync = false;
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
}
- test_BUILT_IN_typedef() {
+ test_BUILT_IN_typedef() async {
addTestFile('''
typedef A();
main() {
var typedef = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
}
- test_BUILT_IN_yield() {
+ test_BUILT_IN_yield() async {
addTestFile('''
main() async* {
yield 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
}
- test_BUILT_IN_yieldStar() {
+ test_BUILT_IN_yieldStar() async {
addTestFile('''
main() async* {
yield* [];
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
}
- test_CLASS() {
+ test_CLASS() async {
addTestFile('''
class AAA {}
AAA aaa;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
- assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
+ assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
}
- test_CLASS_notDynamic() {
+ test_CLASS_notDynamic() async {
addTestFile('''
dynamic f() {}
''');
- return prepareHighlights().then((_) {
- assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
- });
+ await prepareHighlights();
+ assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
}
- test_CLASS_notVoid() {
+ test_CLASS_notVoid() async {
addTestFile('''
void f() {}
''');
- return prepareHighlights().then((_) {
- assertNoRegion(HighlightRegionType.CLASS, 'void f()');
- });
+ await prepareHighlights();
+ assertNoRegion(HighlightRegionType.CLASS, 'void f()');
}
- test_COMMENT() {
+ test_COMMENT() async {
addTestFile('''
/**
* documentation comment
- */
+ */
void main() {
// end-of-line comment
my_function(1);
@@ -518,14 +487,13 @@
/* block comment */
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
- assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
- assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
+ assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
+ assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
}
- test_CONSTRUCTOR() {
+ test_CONSTRUCTOR() async {
addTestFile('''
class AAA {
AAA() {}
@@ -536,42 +504,37 @@
new AAA.name(42);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
- assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
- assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
- assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
+ assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
+ assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
}
- test_DIRECTIVE() {
+ test_DIRECTIVE() async {
addTestFile('''
library lib;
import 'dart:math';
export 'dart:math';
part 'part.dart';
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
- assertHasStringRegion(
- HighlightRegionType.DIRECTIVE, "import 'dart:math';");
- assertHasStringRegion(
- HighlightRegionType.DIRECTIVE, "export 'dart:math';");
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "import 'dart:math';");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "export 'dart:math';");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
}
- test_DIRECTIVE_partOf() {
+ test_DIRECTIVE_partOf() async {
addTestFile('''
part of lib;
''');
_addLibraryForTestPart();
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
}
- test_DYNAMIC_TYPE() {
+ test_DYNAMIC_TYPE() async {
addTestFile('''
f() {}
main(p) {
@@ -581,26 +544,24 @@
var v3 = v2;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'p)');
- assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'v1 =');
- assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v2;');
- assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v3 =');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'p)');
+ assertHasRegion(HighlightRegionType.DYNAMIC_TYPE, 'v1 =');
+ assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v2;');
+ assertNoRegion(HighlightRegionType.DYNAMIC_TYPE, 'v3 =');
}
- test_ENUM() {
+ test_ENUM() async {
addTestFile('''
enum MyEnum {A, B, C}
MyEnum value;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
- assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
+ assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
}
- test_ENUM_CONSTANT() {
+ test_ENUM_CONSTANT() async {
addTestFile('''
enum MyEnum {AAA, BBB}
main() {
@@ -608,15 +569,14 @@
print(MyEnum.BBB);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
}
- test_FIELD() {
+ test_FIELD() async {
addTestFile('''
class A {
int aaa = 1;
@@ -628,16 +588,15 @@
a.bbb = 5;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.FIELD, 'aaa = 1');
- assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
- assertHasRegion(HighlightRegionType.FIELD, 'bbb = 3');
- assertHasRegion(HighlightRegionType.FIELD, 'aaa = 4');
- assertHasRegion(HighlightRegionType.FIELD, 'bbb = 5');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.FIELD, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
+ assertHasRegion(HighlightRegionType.FIELD, 'bbb = 3');
+ assertHasRegion(HighlightRegionType.FIELD, 'aaa = 4');
+ assertHasRegion(HighlightRegionType.FIELD, 'bbb = 5');
}
- test_FIELD_STATIC() {
+ test_FIELD_STATIC() async {
addTestFile('''
class A {
static aaa = 1;
@@ -650,40 +609,37 @@
A.ccc = 3;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 1');
- assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 2');
- assertHasRegion(HighlightRegionType.FIELD_STATIC, 'bbb;');
- assertHasRegion(HighlightRegionType.FIELD_STATIC, 'ccc = 3');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.FIELD_STATIC, 'aaa = 2');
+ assertHasRegion(HighlightRegionType.FIELD_STATIC, 'bbb;');
+ assertHasRegion(HighlightRegionType.FIELD_STATIC, 'ccc = 3');
}
- test_FUNCTION() {
+ test_FUNCTION() async {
addTestFile('''
fff(p) {}
main() {
fff(42);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.FUNCTION_DECLARATION, 'fff(p) {}');
- assertHasRegion(HighlightRegionType.FUNCTION, 'fff(42)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.FUNCTION_DECLARATION, 'fff(p) {}');
+ assertHasRegion(HighlightRegionType.FUNCTION, 'fff(42)');
}
- test_FUNCTION_TYPE_ALIAS() {
+ test_FUNCTION_TYPE_ALIAS() async {
addTestFile('''
typedef FFF(p);
main(FFF fff) {
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
}
- test_GETTER_DECLARATION() {
+ test_GETTER_DECLARATION() async {
addTestFile('''
get aaa => null;
class A {
@@ -694,15 +650,14 @@
a.bbb;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'aaa => null');
- assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'bbb => null');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa;');
- assertHasRegion(HighlightRegionType.FIELD, 'bbb;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'aaa => null');
+ assertHasRegion(HighlightRegionType.GETTER_DECLARATION, 'bbb => null');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa;');
+ assertHasRegion(HighlightRegionType.FIELD, 'bbb;');
}
- test_IDENTIFIER_DEFAULT() {
+ test_IDENTIFIER_DEFAULT() async {
addTestFile('''
main() {
aaa = 42;
@@ -710,27 +665,25 @@
CCC ccc;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
}
- test_IMPORT_PREFIX() {
+ test_IMPORT_PREFIX() async {
addTestFile('''
import 'dart:math' as ma;
main() {
ma.max(1, 2);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
- assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
+ assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
}
- test_KEYWORD() {
+ test_KEYWORD() async {
addTestFile('''
main() {
assert(true);
@@ -763,49 +716,47 @@
}
class C = Object with A;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
- assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
- assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
- assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
- assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
- assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
- assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
- assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
- assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
- assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
- assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
- assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
- assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
- assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
}
- test_KEYWORD_void() {
+ test_KEYWORD_void() async {
addTestFile('''
void main() {
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
}
- test_LABEL() {
+ test_LABEL() async {
addTestFile('''
main() {
myLabel:
@@ -814,57 +765,50 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
- assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
+ assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
}
- test_LITERAL_BOOLEAN() {
+ test_LITERAL_BOOLEAN() async {
addTestFile('var V = true;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
}
- test_LITERAL_DOUBLE() {
+ test_LITERAL_DOUBLE() async {
addTestFile('var V = 4.2;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
}
- test_LITERAL_INTEGER() {
+ test_LITERAL_INTEGER() async {
addTestFile('var V = 42;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
}
- test_LITERAL_LIST() {
+ test_LITERAL_LIST() async {
addTestFile('var V = <int>[1, 2, 3];');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
}
- test_LITERAL_MAP() {
+ test_LITERAL_MAP() async {
addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
- "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+ "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
}
- test_LITERAL_STRING() {
+ test_LITERAL_STRING() async {
addTestFile('var V = "abc";');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
}
- test_LOCAL_VARIABLE() {
+ test_LOCAL_VARIABLE() async {
addTestFile('''
main() {
int vvv = 0;
@@ -872,15 +816,13 @@
vvv = 1;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
- assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv;');
- assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv = 1;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv;');
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE, 'vvv = 1;');
}
- test_METHOD() {
+ test_METHOD() async {
addTestFile('''
class A {
aaa() {}
@@ -893,18 +835,16 @@
A.bbb;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.METHOD_DECLARATION, 'aaa() {}');
- assertHasRegion(
- HighlightRegionType.METHOD_DECLARATION_STATIC, 'bbb() {}');
- assertHasRegion(HighlightRegionType.METHOD, 'aaa();');
- assertHasRegion(HighlightRegionType.METHOD, 'aaa;');
- assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb();');
- assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.METHOD_DECLARATION, 'aaa() {}');
+ assertHasRegion(HighlightRegionType.METHOD_DECLARATION_STATIC, 'bbb() {}');
+ assertHasRegion(HighlightRegionType.METHOD, 'aaa();');
+ assertHasRegion(HighlightRegionType.METHOD, 'aaa;');
+ assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb();');
+ assertHasRegion(HighlightRegionType.METHOD_STATIC, 'bbb;');
}
- test_METHOD_bestType() {
+ test_METHOD_bestType() async {
addTestFile('''
main(p) {
if (p is List) {
@@ -912,26 +852,24 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.METHOD, 'add(null)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.METHOD, 'add(null)');
}
- test_PARAMETER() {
+ test_PARAMETER() async {
addTestFile('''
main(int p) {
p;
p = 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.PARAMETER, 'p) {');
- assertHasRegion(HighlightRegionType.PARAMETER, 'p;');
- assertHasRegion(HighlightRegionType.PARAMETER, 'p = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.PARAMETER, 'p) {');
+ assertHasRegion(HighlightRegionType.PARAMETER, 'p;');
+ assertHasRegion(HighlightRegionType.PARAMETER, 'p = 42');
}
- test_SETTER_DECLARATION() {
+ test_SETTER_DECLARATION() async {
addTestFile('''
set aaa(x) {}
class A {
@@ -942,15 +880,14 @@
a.bbb = 2;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'aaa(x)');
- assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'bbb(x)');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa = 1');
- assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'aaa(x)');
+ assertHasRegion(HighlightRegionType.SETTER_DECLARATION, 'bbb(x)');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.FIELD, 'bbb = 2');
}
- test_TOP_LEVEL_VARIABLE() {
+ test_TOP_LEVEL_VARIABLE() async {
addTestFile('''
const VVV = 0;
@VVV // annotation
@@ -959,41 +896,38 @@
VVV = 1;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 0');
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV // annotation');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV);');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 1');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 0');
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV // annotation');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV);');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_VARIABLE, 'VVV = 1');
}
- test_TYPE_NAME_DYNAMIC() {
+ test_TYPE_NAME_DYNAMIC() async {
addTestFile('''
dynamic main() {
dynamic = 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
- assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
- assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
+ assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
+ assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
}
- test_TYPE_PARAMETER() {
+ test_TYPE_PARAMETER() async {
addTestFile('''
class A<T> {
T fff;
T mmm(T p) => null;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
}
void _addLibraryForTestPart() {
diff --git a/pkg/analysis_server/test/analysis/notification_highlights_test2.dart b/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
index 28eda94..0342c89 100644
--- a/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
+++ b/pkg/analysis_server/test/analysis/notification_highlights_test2.dart
@@ -109,58 +109,54 @@
createProject();
}
- test_ANNOTATION_hasArguments() {
+ test_ANNOTATION_hasArguments() async {
addTestFile('''
class AAA {
const AAA(a, b, c);
}
@AAA(1, 2, 3) main() {}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
- assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA(', '@AAA('.length);
+ assertHasRegion(HighlightRegionType.ANNOTATION, ') main', ')'.length);
}
- test_ANNOTATION_noArguments() {
+ test_ANNOTATION_noArguments() async {
addTestFile('''
const AAA = 42;
@AAA main() {}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ANNOTATION, '@AAA');
}
- test_BUILT_IN_abstract() {
+ test_BUILT_IN_abstract() async {
addTestFile('''
abstract class A {};
abstract class B = Object with A;
main() {
var abstract = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class A');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'abstract class B');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'abstract = 42');
}
- test_BUILT_IN_as() {
+ test_BUILT_IN_as() async {
addTestFile('''
import 'dart:math' as math;
main() {
p as int;
var as = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'as math');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'as int');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'as = 42');
}
- test_BUILT_IN_async() {
+ test_BUILT_IN_async() async {
addTestFile('''
fa() async {}
fb() async* {}
@@ -168,14 +164,13 @@
bool async = false;
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async');
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'async*');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'async = false');
}
- test_BUILT_IN_await() {
+ test_BUILT_IN_await() async {
addTestFile('''
main() async {
await 42;
@@ -184,37 +179,34 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'await 42');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'await for');
}
- test_BUILT_IN_deferred() {
+ test_BUILT_IN_deferred() async {
addTestFile('''
import 'dart:math' deferred as math;
main() {
var deferred = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'deferred as math');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'deferred = 42');
}
- test_BUILT_IN_export() {
+ test_BUILT_IN_export() async {
addTestFile('''
export "dart:math";
main() {
var export = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'export "dart:');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'export = 42');
}
- test_BUILT_IN_external() {
+ test_BUILT_IN_external() async {
addTestFile('''
class A {
external A();
@@ -223,15 +215,14 @@
external main() {
var external = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external A()');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external aaa()');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'external main()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'external = 42');
}
- test_BUILT_IN_factory() {
+ test_BUILT_IN_factory() async {
addTestFile('''
class A {
factory A() => null;
@@ -239,13 +230,12 @@
main() {
var factory = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'factory A()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'factory = 42');
}
- test_BUILT_IN_get() {
+ test_BUILT_IN_get() async {
addTestFile('''
get aaa => 1;
class A {
@@ -254,63 +244,58 @@
main() {
var get = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'get aaa =>');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'get bbb =>');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'get = 42');
}
- test_BUILT_IN_hide() {
+ test_BUILT_IN_hide() async {
addTestFile('''
import 'foo.dart' hide Foo;
main() {
var hide = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'hide Foo');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'hide = 42');
}
- test_BUILT_IN_implements() {
+ test_BUILT_IN_implements() async {
addTestFile('''
class A {}
class B implements A {}
main() {
var implements = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'implements A {}');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'implements = 42');
}
- test_BUILT_IN_import() {
+ test_BUILT_IN_import() async {
addTestFile('''
import "foo.dart";
main() {
var import = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'import "');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'import = 42');
}
- test_BUILT_IN_library() {
+ test_BUILT_IN_library() async {
addTestFile('''
library lib;
main() {
var library = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'library lib;');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'library = 42');
}
- test_BUILT_IN_native() {
+ test_BUILT_IN_native() async {
addTestFile('''
class A native "A_native" {}
class B {
@@ -319,14 +304,13 @@
main() {
var native = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'native "A_');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'native "bbb_');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'native = 42');
}
- test_BUILT_IN_on() {
+ test_BUILT_IN_on() async {
addTestFile('''
main() {
try {
@@ -334,13 +318,12 @@
}
var on = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'on int');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'on = 42');
}
- test_BUILT_IN_operator() {
+ test_BUILT_IN_operator() async {
addTestFile('''
class A {
operator +(x) => null;
@@ -348,26 +331,24 @@
main() {
var operator = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'operator +(');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'operator = 42');
}
- test_BUILT_IN_part() {
+ test_BUILT_IN_part() async {
addTestFile('''
part "my_part.dart";
main() {
var part = 42;
}''');
addFile('/project/bin/my_part.dart', 'part of lib;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'part "my_');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 42');
}
- test_BUILT_IN_partOf() {
+ test_BUILT_IN_partOf() async {
addTestFile('''
part of lib;
main() {
@@ -375,15 +356,13 @@
var of = 2;
}''');
_addLibraryForTestPart();
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
- assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'part of', 'part of'.length);
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'part = 1');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'of = 2');
}
- test_BUILT_IN_set() {
+ test_BUILT_IN_set() async {
addTestFile('''
set aaa(x) {}
class A
@@ -392,26 +371,24 @@
main() {
var set = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'set aaa(');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'set bbb(');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'set = 42');
}
- test_BUILT_IN_show() {
+ test_BUILT_IN_show() async {
addTestFile('''
import 'foo.dart' show Foo;
main() {
var show = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'show Foo');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'show = 42');
}
- test_BUILT_IN_static() {
+ test_BUILT_IN_static() async {
addTestFile('''
class A {
static aaa;
@@ -420,14 +397,13 @@
main() {
var static = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
- assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'static aaa;');
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'static bbb()');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'static = 42');
}
- test_BUILT_IN_sync() {
+ test_BUILT_IN_sync() async {
addTestFile('''
fa() sync {}
fb() sync* {}
@@ -435,81 +411,74 @@
bool sync = false;
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync');
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'sync*');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'sync = false');
}
- test_BUILT_IN_typedef() {
+ test_BUILT_IN_typedef() async {
addTestFile('''
typedef A();
main() {
var typedef = 42;
}''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
- assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'typedef A();');
+ assertNoRegion(HighlightRegionType.BUILT_IN, 'typedef = 42');
}
- test_BUILT_IN_yield() {
+ test_BUILT_IN_yield() async {
addTestFile('''
main() async* {
yield 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.BUILT_IN, 'yield 42');
}
- test_BUILT_IN_yieldStar() {
+ test_BUILT_IN_yieldStar() async {
addTestFile('''
main() async* {
yield* [];
}
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.BUILT_IN, 'yield*');
}
- test_CLASS() {
+ test_CLASS() async {
addTestFile('''
class AAA {}
AAA aaa;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
- assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CLASS, 'AAA {}');
+ assertHasRegion(HighlightRegionType.CLASS, 'AAA aaa');
}
- test_CLASS_notDynamic() {
+ test_CLASS_notDynamic() async {
addTestFile('''
dynamic f() {}
''');
- return prepareHighlights().then((_) {
- assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
- });
+ await prepareHighlights();
+ assertNoRegion(HighlightRegionType.CLASS, 'dynamic f()');
}
- test_CLASS_notVoid() {
+ test_CLASS_notVoid() async {
addTestFile('''
void f() {}
''');
- return prepareHighlights().then((_) {
- assertNoRegion(HighlightRegionType.CLASS, 'void f()');
- });
+ await prepareHighlights();
+ assertNoRegion(HighlightRegionType.CLASS, 'void f()');
}
- test_COMMENT() {
+ test_COMMENT() async {
addTestFile('''
/**
* documentation comment
- */
+ */
void main() {
// end-of-line comment
my_function(1);
@@ -519,14 +488,13 @@
/* block comment */
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
- assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
- assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.COMMENT_DOCUMENTATION, '/**', 32);
+ assertHasRegion(HighlightRegionType.COMMENT_END_OF_LINE, '//', 22);
+ assertHasRegion(HighlightRegionType.COMMENT_BLOCK, '/* b', 19);
}
- test_CONSTRUCTOR() {
+ test_CONSTRUCTOR() async {
addTestFile('''
class AAA {
AAA() {}
@@ -537,42 +505,37 @@
new AAA.name(42);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
- assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
- assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
- assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(p)');
+ assertHasRegion(HighlightRegionType.CONSTRUCTOR, 'name(42)');
+ assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA() {}');
+ assertNoRegion(HighlightRegionType.CONSTRUCTOR, 'AAA();');
}
- test_DIRECTIVE() {
+ test_DIRECTIVE() async {
addTestFile('''
library lib;
import 'dart:math';
export 'dart:math';
part 'part.dart';
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
- assertHasStringRegion(
- HighlightRegionType.DIRECTIVE, "import 'dart:math';");
- assertHasStringRegion(
- HighlightRegionType.DIRECTIVE, "export 'dart:math';");
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "library lib;");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "import 'dart:math';");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "export 'dart:math';");
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part 'part.dart';");
}
- test_DIRECTIVE_partOf() {
+ test_DIRECTIVE_partOf() async {
addTestFile('''
part of lib;
''');
_addLibraryForTestPart();
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.DIRECTIVE, "part of lib;");
}
- test_DYNAMIC_LOCAL_VARIABLE() {
+ test_DYNAMIC_LOCAL_VARIABLE() async {
addTestFile('''
f() {}
main(p) {
@@ -580,27 +543,24 @@
v;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION, 'v = f()');
- assertHasRegion(
- HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE, 'v;');
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION, 'v = f()');
+ assertHasRegion(HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE, 'v;');
}
- test_DYNAMIC_PARAMETER() {
+ test_DYNAMIC_PARAMETER() async {
addTestFile('''
main(p) {
print(p);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION, 'p)');
- assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE, 'p);');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION, 'p)');
+ assertHasRegion(HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE, 'p);');
}
- test_DYNAMIC_VARIABLE_field() {
+ test_DYNAMIC_VARIABLE_field() async {
addTestFile('''
class A {
var f;
@@ -609,24 +569,22 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
- assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'f = 1');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
+ assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'f = 1');
}
- test_ENUM() {
+ test_ENUM() async {
addTestFile('''
enum MyEnum {A, B, C}
MyEnum value;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
- assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ENUM, 'MyEnum {');
+ assertHasRegion(HighlightRegionType.ENUM, 'MyEnum value;');
}
- test_ENUM_CONSTANT() {
+ test_ENUM_CONSTANT() async {
addTestFile('''
enum MyEnum {AAA, BBB}
main() {
@@ -634,27 +592,25 @@
print(MyEnum.BBB);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
- assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA, ');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB}');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'AAA);');
+ assertHasRegion(HighlightRegionType.ENUM_CONSTANT, 'BBB);');
}
- test_FUNCTION_TYPE_ALIAS() {
+ test_FUNCTION_TYPE_ALIAS() async {
addTestFile('''
typedef FFF(p);
main(FFF fff) {
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
- assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF(p)');
+ assertHasRegion(HighlightRegionType.FUNCTION_TYPE_ALIAS, 'FFF fff)');
}
- test_GETTER() {
+ test_GETTER() async {
addTestFile('''
get aaa => null;
class A {
@@ -667,20 +623,19 @@
A.ccc;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION, 'aaa => null');
- assertHasRegion(
- HighlightRegionType.INSTANCE_GETTER_DECLARATION, 'bbb => null');
- assertHasRegion(
- HighlightRegionType.STATIC_GETTER_DECLARATION, 'ccc => null');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'aaa;');
- assertHasRegion(HighlightRegionType.INSTANCE_GETTER_REFERENCE, 'bbb;');
- assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'ccc;');
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_GETTER_DECLARATION, 'aaa => null');
+ assertHasRegion(
+ HighlightRegionType.INSTANCE_GETTER_DECLARATION, 'bbb => null');
+ assertHasRegion(
+ HighlightRegionType.STATIC_GETTER_DECLARATION, 'ccc => null');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'aaa;');
+ assertHasRegion(HighlightRegionType.INSTANCE_GETTER_REFERENCE, 'bbb;');
+ assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'ccc;');
}
- test_IDENTIFIER_DEFAULT() {
+ test_IDENTIFIER_DEFAULT() async {
addTestFile('''
main() {
aaa = 42;
@@ -688,27 +643,25 @@
CCC ccc;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
- assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'aaa = 42');
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'bbb(84)');
+ assertHasRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'CCC ccc');
}
- test_IMPORT_PREFIX() {
+ test_IMPORT_PREFIX() async {
addTestFile('''
import 'dart:math' as ma;
main() {
ma.max(1, 2);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
- assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma;');
+ assertHasRegion(HighlightRegionType.IMPORT_PREFIX, 'ma.max');
}
- test_INSTANCE_FIELD() {
+ test_INSTANCE_FIELD() async {
addTestFile('''
class A {
int aaa = 1;
@@ -720,31 +673,27 @@
a.bbb = 5;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'aaa = 1');
- assertHasRegion(
- HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'bbb = 2');
- assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'bbb = 3');
- assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'aaa = 4');
- assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 5');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'bbb = 2');
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'bbb = 3');
+ assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'aaa = 4');
+ assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 5');
}
- test_INSTANCE_FIELD_dynamic() {
+ test_INSTANCE_FIELD_dynamic() async {
addTestFile('''
class A {
var f;
A(this.f);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
- assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'f);');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_DECLARATION, 'f;');
+ assertHasRegion(HighlightRegionType.INSTANCE_FIELD_REFERENCE, 'f);');
}
- test_KEYWORD() {
+ test_KEYWORD() async {
addTestFile('''
main() {
assert(true);
@@ -777,49 +726,47 @@
}
class C = Object with A;
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
- assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
- assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
- assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
- assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
- assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
- assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
- assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
- assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
- assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
- assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
- assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
- assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
- assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
- assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
- assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
- assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.KEYWORD, 'assert(true)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'for (;;)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'for (var v4 in');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'break;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'case 0:');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'catch (e) {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'class A {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'const v1');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'continue;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'default:');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'do {} while');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'if (true)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'false;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'final v3 =');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'finally {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'in []');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'is int');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'new A();');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'rethrow;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'return this');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'super();');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'switch (0)');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'this;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'true;');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'try {');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'while (true) {}');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'while (true);');
+ assertHasRegion(HighlightRegionType.KEYWORD, 'with A;');
}
- test_KEYWORD_void() {
+ test_KEYWORD_void() async {
addTestFile('''
void main() {
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.KEYWORD, 'void main()');
}
- test_LABEL() {
+ test_LABEL() async {
addTestFile('''
main() {
myLabel:
@@ -828,76 +775,67 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
- assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LABEL, 'myLabel:');
+ assertHasRegion(HighlightRegionType.LABEL, 'myLabel;');
}
- test_LIBRARY_NAME_libraryDirective() {
+ test_LIBRARY_NAME_libraryDirective() async {
addTestFile('''
library my.lib.name;
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
}
- test_LIBRARY_NAME_partOfDirective() {
+ test_LIBRARY_NAME_partOfDirective() async {
_addLibraryForTestPart();
addTestFile('''
part of my.lib.name;
''');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LIBRARY_NAME, 'my.lib.name');
}
- test_LITERAL_BOOLEAN() {
+ test_LITERAL_BOOLEAN() async {
addTestFile('var V = true;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_BOOLEAN, 'true;');
}
- test_LITERAL_DOUBLE() {
+ test_LITERAL_DOUBLE() async {
addTestFile('var V = 4.2;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_DOUBLE, '4.2;', '4.2'.length);
}
- test_LITERAL_INTEGER() {
+ test_LITERAL_INTEGER() async {
addTestFile('var V = 42;');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LITERAL_INTEGER, '42;');
}
- test_LITERAL_LIST() {
+ test_LITERAL_LIST() async {
addTestFile('var V = <int>[1, 2, 3];');
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LITERAL_LIST, '<int>[1, 2, 3]');
}
- test_LITERAL_MAP() {
+ test_LITERAL_MAP() async {
addTestFile("var V = const <int, String>{1: 'a', 2: 'b', 3: 'c'};");
- return prepareHighlights().then((_) {
- assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
- "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
- });
+ await prepareHighlights();
+ assertHasStringRegion(HighlightRegionType.LITERAL_MAP,
+ "const <int, String>{1: 'a', 2: 'b', 3: 'c'}");
}
- test_LITERAL_STRING() {
+ test_LITERAL_STRING() async {
addTestFile('var V = "abc";');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.LITERAL_STRING, '"abc";', '"abc"'.length);
}
- test_LOCAL_FUNCTION() {
+ test_LOCAL_FUNCTION() async {
addTestFile('''
main() {
fff() {}
@@ -905,15 +843,13 @@
fff;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.LOCAL_FUNCTION_DECLARATION, 'fff() {}');
- assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff();');
- assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_DECLARATION, 'fff() {}');
+ assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff();');
+ assertHasRegion(HighlightRegionType.LOCAL_FUNCTION_REFERENCE, 'fff;');
}
- test_LOCAL_VARIABLE() {
+ test_LOCAL_VARIABLE() async {
addTestFile('''
main() {
int vvv = 0;
@@ -921,15 +857,13 @@
vvv = 1;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
- assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv;');
- assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv = 1;');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_DECLARATION, 'vvv = 0');
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv;');
+ assertHasRegion(HighlightRegionType.LOCAL_VARIABLE_REFERENCE, 'vvv = 1;');
}
- test_METHOD() {
+ test_METHOD() async {
addTestFile('''
class A {
aaa() {}
@@ -942,19 +876,17 @@
A.bbb;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.INSTANCE_METHOD_DECLARATION, 'aaa() {}');
- assertHasRegion(
- HighlightRegionType.STATIC_METHOD_DECLARATION, 'bbb() {}');
- assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa();');
- assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa;');
- assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb();');
- assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb;');
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.INSTANCE_METHOD_DECLARATION, 'aaa() {}');
+ assertHasRegion(HighlightRegionType.STATIC_METHOD_DECLARATION, 'bbb() {}');
+ assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa();');
+ assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'aaa;');
+ assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb();');
+ assertHasRegion(HighlightRegionType.STATIC_METHOD_REFERENCE, 'bbb;');
}
- test_METHOD_bestType() {
+ test_METHOD_bestType() async {
addTestFile('''
main(p) {
if (p is List) {
@@ -962,27 +894,24 @@
}
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'add(null)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.INSTANCE_METHOD_REFERENCE, 'add(null)');
}
- test_PARAMETER() {
+ test_PARAMETER() async {
addTestFile('''
main(int p) {
p;
p = 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.PARAMETER_DECLARATION, 'p) {');
- assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p;');
- assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.PARAMETER_DECLARATION, 'p) {');
+ assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p;');
+ assertHasRegion(HighlightRegionType.PARAMETER_REFERENCE, 'p = 42');
}
- test_SETTER_DECLARATION() {
+ test_SETTER_DECLARATION() async {
addTestFile('''
set aaa(x) {}
class A {
@@ -995,20 +924,16 @@
A.ccc = 3;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION, 'aaa(x)');
- assertHasRegion(
- HighlightRegionType.INSTANCE_SETTER_DECLARATION, 'bbb(x)');
- assertHasRegion(HighlightRegionType.STATIC_SETTER_DECLARATION, 'ccc(x)');
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'aaa = 1');
- assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 2');
- assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_DECLARATION, 'aaa(x)');
+ assertHasRegion(HighlightRegionType.INSTANCE_SETTER_DECLARATION, 'bbb(x)');
+ assertHasRegion(HighlightRegionType.STATIC_SETTER_DECLARATION, 'ccc(x)');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.INSTANCE_SETTER_REFERENCE, 'bbb = 2');
+ assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
}
- test_STATIC_FIELD() {
+ test_STATIC_FIELD() async {
addTestFile('''
class A {
static aaa = 1;
@@ -1021,30 +946,28 @@
A.ccc = 3;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.STATIC_FIELD_DECLARATION, 'aaa = 1');
- assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'aaa = 2');
- assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'bbb;');
- assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.STATIC_FIELD_DECLARATION, 'aaa = 1');
+ assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'aaa = 2');
+ assertHasRegion(HighlightRegionType.STATIC_GETTER_REFERENCE, 'bbb;');
+ assertHasRegion(HighlightRegionType.STATIC_SETTER_REFERENCE, 'ccc = 3');
}
- test_TOP_LEVEL_FUNCTION() {
+ test_TOP_LEVEL_FUNCTION() async {
addTestFile('''
fff(p) {}
main() {
fff(42);
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION, 'fff(p) {}');
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE, 'fff(42)');
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_FUNCTION_DECLARATION, 'fff(p) {}');
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_FUNCTION_REFERENCE, 'fff(42)');
}
- test_TOP_LEVEL_VARIABLE() {
+ test_TOP_LEVEL_VARIABLE() async {
addTestFile('''
const V1 = 1;
var V2 = 2;
@@ -1054,47 +977,44 @@
V2 = 3;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V1 = 1');
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V2 = 2');
- assertHasRegion(
- HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1 // annotation');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1);');
- assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'V2 = 3');
- });
+ await prepareHighlights();
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V1 = 1');
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_VARIABLE_DECLARATION, 'V2 = 2');
+ assertHasRegion(
+ HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1 // annotation');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_GETTER_REFERENCE, 'V1);');
+ assertHasRegion(HighlightRegionType.TOP_LEVEL_SETTER_REFERENCE, 'V2 = 3');
}
- test_TYPE_NAME_DYNAMIC() {
+ test_TYPE_NAME_DYNAMIC() async {
addTestFile('''
dynamic main() {
dynamic = 42;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
- assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
- assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic main()');
+ assertNoRegion(HighlightRegionType.IDENTIFIER_DEFAULT, 'dynamic main()');
+ assertNoRegion(HighlightRegionType.TYPE_NAME_DYNAMIC, 'dynamic = 42');
}
- test_TYPE_PARAMETER() {
+ test_TYPE_PARAMETER() async {
addTestFile('''
class A<T> {
T fff;
T mmm(T p) => null;
}
''');
- return prepareHighlights().then((_) {
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
- assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
- });
+ await prepareHighlights();
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T> {');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T fff;');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T mmm(');
+ assertHasRegion(HighlightRegionType.TYPE_PARAMETER, 'T p)');
}
- test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_dynamicVarTarget() {
+ test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_dynamicVarTarget() async {
addTestFile('''
main(p) {
p.aaa;
@@ -1106,20 +1026,19 @@
''.length.ccc().ddd();
}
''');
- return prepareHighlights().then((_) {
- HighlightRegionType type =
- HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
- assertHasRegion(type, 'aaa');
- assertHasRegion(type, 'aaa++');
- assertHasRegion(type, 'aaa += 0');
- assertHasRegion(type, 'aaa; // ++');
- assertHasRegion(type, 'aaa =');
- assertHasRegion(type, 'bbb(');
- assertHasRegion(type, 'ddd()');
- });
+ await prepareHighlights();
+ HighlightRegionType type =
+ HighlightRegionType.UNRESOLVED_INSTANCE_MEMBER_REFERENCE;
+ assertHasRegion(type, 'aaa');
+ assertHasRegion(type, 'aaa++');
+ assertHasRegion(type, 'aaa += 0');
+ assertHasRegion(type, 'aaa; // ++');
+ assertHasRegion(type, 'aaa =');
+ assertHasRegion(type, 'bbb(');
+ assertHasRegion(type, 'ddd()');
}
- test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_nonDynamicTarget() {
+ test_UNRESOLVED_INSTANCE_MEMBER_REFERENCE_nonDynamicTarget() async {
addTestFile('''
import 'dart:math' as math;
main(String str) {
@@ -1135,15 +1054,14 @@
}
}
''');
- return prepareHighlights().then((_) {
- HighlightRegionType type = HighlightRegionType.IDENTIFIER_DEFAULT;
- assertHasRegion(type, 'aaa()');
- assertHasRegion(type, 'bbb()');
- assertHasRegion(type, 'ccc()');
- assertHasRegion(type, 'unresolved(1)');
- assertHasRegion(type, 'unresolved(2)');
- assertHasRegion(type, 'unresolved(3)');
- });
+ await prepareHighlights();
+ HighlightRegionType type = HighlightRegionType.IDENTIFIER_DEFAULT;
+ assertHasRegion(type, 'aaa()');
+ assertHasRegion(type, 'bbb()');
+ assertHasRegion(type, 'ccc()');
+ assertHasRegion(type, 'unresolved(1)');
+ assertHasRegion(type, 'unresolved(2)');
+ assertHasRegion(type, 'unresolved(3)');
}
void _addLibraryForTestPart() {
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index 5c1c6ed..d5cde86 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -315,6 +315,84 @@
assertHasImplementedMember('f(_) {} // A');
}
+ test_static_field_instanceStatic() async {
+ addTestFile('''
+class A {
+ int F = 0;
+}
+class B extends A {
+ static int F = 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('F = 0');
+ }
+
+ test_static_field_staticInstance() async {
+ addTestFile('''
+class A {
+ static int F = 0;
+}
+class B extends A {
+ int F = 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('F = 0');
+ }
+
+ test_static_field_staticStatic() async {
+ addTestFile('''
+class A {
+ static int F = 0;
+}
+class B extends A {
+ static int F = 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('F = 0');
+ }
+
+ test_static_method_instanceStatic() async {
+ addTestFile('''
+class A {
+ int m() => 0;
+}
+class B extends A {
+ static int m() => 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('m() => 0');
+ }
+
+ test_static_method_staticInstance() async {
+ addTestFile('''
+class A {
+ static int m() => 0;
+}
+class B extends A {
+ int m() => 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('m() => 0');
+ }
+
+ test_static_method_staticStatic() async {
+ addTestFile('''
+class A {
+ static int m() => 0;
+}
+class B extends A {
+ static int m() => 1;
+}
+''');
+ await prepareImplementedElements();
+ assertNoImplementedMember('m() => 0');
+ }
+
Future waitForImplementedElements() {
Future waitForNotification(int times) {
if (times == 0 || implementedClasses != null) {
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index 68b347c..2e56daa 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -179,11 +179,10 @@
@reflectiveTest
class AnalysisNotificationNavigationTest extends AbstractNavigationTest {
- Future prepareNavigation() {
+ Future prepareNavigation() async {
addAnalysisSubscription(AnalysisService.NAVIGATION, testFile);
- return waitForTasksFinished().then((_) {
- assertRegionsSorted();
- });
+ await waitForTasksFinished();
+ assertRegionsSorted();
}
void processNotification(Notification notification) {
@@ -203,16 +202,14 @@
createProject();
}
- test_afterAnalysis() {
+ test_afterAnalysis() async {
addTestFile('''
class AAA {}
AAA aaa;
''');
- return waitForTasksFinished().then((_) {
- return prepareNavigation().then((_) {
- assertHasRegionTarget('AAA aaa;', 'AAA {}');
- });
- });
+ await waitForTasksFinished();
+ await prepareNavigation();
+ assertHasRegionTarget('AAA aaa;', 'AAA {}');
}
test_annotationConstructor_implicit() async {
@@ -322,55 +319,52 @@
assertHasRegion('myan // ref');
}
- test_class_fromSDK() {
+ test_class_fromSDK() async {
addTestFile('''
int V = 42;
''');
- return prepareNavigation().then((_) {
- assertHasRegion('int V');
- int targetIndex = testTargetIndexes[0];
- NavigationTarget target = targets[targetIndex];
- expect(target.startLine, greaterThan(0));
- expect(target.startColumn, greaterThan(0));
- });
+ await prepareNavigation();
+ assertHasRegion('int V');
+ int targetIndex = testTargetIndexes[0];
+ NavigationTarget target = targets[targetIndex];
+ expect(target.startLine, greaterThan(0));
+ expect(target.startColumn, greaterThan(0));
}
- test_constructor_named() {
+ test_constructor_named() async {
addTestFile('''
class A {
A.named(BBB p) {}
}
class BBB {}
''');
- return prepareNavigation().then((_) {
- // has region for complete "A.named"
- assertHasRegionString('A.named');
- assertHasTarget('named(BBB');
- // no separate regions for "A" and "named"
- assertNoRegion('A.named(', 'A'.length);
- assertNoRegion('named(', 'named'.length);
- // validate that we don't forget to resolve parameters
- assertHasRegionTarget('BBB p', 'BBB {}');
- });
+ await prepareNavigation();
+ // has region for complete "A.named"
+ assertHasRegionString('A.named');
+ assertHasTarget('named(BBB');
+ // no separate regions for "A" and "named"
+ assertNoRegion('A.named(', 'A'.length);
+ assertNoRegion('named(', 'named'.length);
+ // validate that we don't forget to resolve parameters
+ assertHasRegionTarget('BBB p', 'BBB {}');
}
- test_constructor_unnamed() {
+ test_constructor_unnamed() async {
addTestFile('''
class A {
A(BBB p) {}
}
class BBB {}
''');
- return prepareNavigation().then((_) {
- // has region for complete "A.named"
- assertHasRegion("A(BBB");
- assertHasTarget("A(BBB", 0);
- // validate that we don't forget to resolve parameters
- assertHasRegionTarget('BBB p', 'BBB {}');
- });
+ await prepareNavigation();
+ // has region for complete "A.named"
+ assertHasRegion("A(BBB");
+ assertHasTarget("A(BBB", 0);
+ // validate that we don't forget to resolve parameters
+ assertHasRegionTarget('BBB p', 'BBB {}');
}
- test_factoryRedirectingConstructor_implicit() {
+ test_factoryRedirectingConstructor_implicit() async {
addTestFile('''
class A {
factory A() = B;
@@ -378,13 +372,12 @@
class B {
}
''');
- return prepareNavigation().then((_) {
- assertHasRegion('B;');
- assertHasTarget('B {');
- });
+ await prepareNavigation();
+ assertHasRegion('B;');
+ assertHasTarget('B {');
}
- test_factoryRedirectingConstructor_implicit_withTypeArgument() {
+ test_factoryRedirectingConstructor_implicit_withTypeArgument() async {
addTestFile('''
class A {}
class B {
@@ -392,19 +385,18 @@
}
class C<T> {}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegion('C<A>');
- assertHasTarget('C<T> {');
- }
- {
- assertHasRegion('A>;');
- assertHasTarget('A {');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegion('C<A>');
+ assertHasTarget('C<T> {');
+ }
+ {
+ assertHasRegion('A>;');
+ assertHasTarget('A {');
+ }
}
- test_factoryRedirectingConstructor_named() {
+ test_factoryRedirectingConstructor_named() async {
addTestFile('''
class A {
factory A() = B.named;
@@ -413,19 +405,18 @@
B.named();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('B.named;', 'B'.length);
- assertHasTarget('named();');
- }
- {
- assertHasRegionString('named;', 'named'.length);
- assertHasTarget('named();');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegionString('B.named;', 'B'.length);
+ assertHasTarget('named();');
+ }
+ {
+ assertHasRegionString('named;', 'named'.length);
+ assertHasTarget('named();');
+ }
}
- test_factoryRedirectingConstructor_named_withTypeArgument() {
+ test_factoryRedirectingConstructor_named_withTypeArgument() async {
addTestFile('''
class A {}
class B {
@@ -435,23 +426,22 @@
C.named() {}
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegion('C<A>');
- assertHasTarget('named() {}');
- }
- {
- assertHasRegion('A>.named');
- assertHasTarget('A {');
- }
- {
- assertHasRegion('named;', 'named'.length);
- assertHasTarget('named() {}');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegion('C<A>');
+ assertHasTarget('named() {}');
+ }
+ {
+ assertHasRegion('A>.named');
+ assertHasTarget('A {');
+ }
+ {
+ assertHasRegion('named;', 'named'.length);
+ assertHasTarget('named() {}');
+ }
}
- test_factoryRedirectingConstructor_unnamed() {
+ test_factoryRedirectingConstructor_unnamed() async {
addTestFile('''
class A {
factory A() = B;
@@ -460,13 +450,12 @@
B() {}
}
''');
- return prepareNavigation().then((_) {
- assertHasRegion('B;');
- assertHasTarget('B() {}', 0);
- });
+ await prepareNavigation();
+ assertHasRegion('B;');
+ assertHasTarget('B() {}', 0);
}
- test_factoryRedirectingConstructor_unnamed_withTypeArgument() {
+ test_factoryRedirectingConstructor_unnamed_withTypeArgument() async {
addTestFile('''
class A {}
class B {
@@ -476,53 +465,49 @@
C() {}
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegion('C<A>');
- assertHasTarget('C() {}', 0);
- }
- {
- assertHasRegion('A>;');
- assertHasTarget('A {');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegion('C<A>');
+ assertHasTarget('C() {}', 0);
+ }
+ {
+ assertHasRegion('A>;');
+ assertHasTarget('A {');
+ }
}
- test_factoryRedirectingConstructor_unresolved() {
+ test_factoryRedirectingConstructor_unresolved() async {
addTestFile('''
class A {
factory A() = B;
}
''');
- return prepareNavigation().then((_) {
- // don't check regions, but there should be no exceptions
- });
+ await prepareNavigation();
+ // don't check regions, but there should be no exceptions
}
- test_fieldFormalParameter() {
+ test_fieldFormalParameter() async {
addTestFile('''
class AAA {
int fff = 123;
AAA(this.fff);
}
''');
- return prepareNavigation().then((_) {
- assertHasRegionTarget('fff);', 'fff = 123');
- });
+ await prepareNavigation();
+ assertHasRegionTarget('fff);', 'fff = 123');
}
- test_fieldFormalParameter_unresolved() {
+ test_fieldFormalParameter_unresolved() async {
addTestFile('''
class AAA {
AAA(this.fff);
}
''');
- return prepareNavigation().then((_) {
- assertNoRegion('fff);', 3);
- });
+ await prepareNavigation();
+ assertNoRegion('fff);', 3);
}
- test_identifier_resolved() {
+ test_identifier_resolved() async {
addTestFile('''
class AAA {}
main() {
@@ -530,25 +515,23 @@
print(aaa);
}
''');
- return prepareNavigation().then((_) {
- assertHasRegionTarget('AAA aaa', 'AAA {}');
- assertHasRegionTarget('aaa);', 'aaa = null');
- assertHasRegionTarget('main() {', 'main() {');
- });
+ await prepareNavigation();
+ assertHasRegionTarget('AAA aaa', 'AAA {}');
+ assertHasRegionTarget('aaa);', 'aaa = null');
+ assertHasRegionTarget('main() {', 'main() {');
}
- test_identifier_unresolved() {
+ test_identifier_unresolved() async {
addTestFile('''
main() {
print(vvv);
}
''');
- return prepareNavigation().then((_) {
- assertNoRegionString('vvv');
- });
+ await prepareNavigation();
+ assertNoRegionString('vvv');
}
- test_identifier_whenStrayImportDirective() {
+ test_identifier_whenStrayImportDirective() async {
addTestFile('''
main() {
int aaa = 42;
@@ -556,9 +539,8 @@
}
import 'dart:math';
''');
- return prepareNavigation().then((_) {
- assertHasRegionTarget('aaa);', 'aaa = 42');
- });
+ await prepareNavigation();
+ assertHasRegionTarget('aaa);', 'aaa = 42');
}
test_inComment() async {
@@ -578,7 +560,7 @@
assertHasRegionTarget('FirstClass(', 'FirstClass {');
}
- test_instanceCreation_implicit() {
+ test_instanceCreation_implicit() async {
addTestFile('''
class A {
}
@@ -586,13 +568,12 @@
new A();
}
''');
- return prepareNavigation().then((_) {
- assertHasRegionString('A()', 'A'.length);
- assertHasTarget('A {');
- });
+ await prepareNavigation();
+ assertHasRegionString('A()', 'A'.length);
+ assertHasTarget('A {');
}
- test_instanceCreation_implicit_withTypeArgument() {
+ test_instanceCreation_implicit_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {}
@@ -600,19 +581,18 @@
new B<A>();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegion('B<A>', 'B'.length);
- assertHasTarget('B<T> {');
- }
- {
- assertHasRegion('A>();', 'A'.length);
- assertHasTarget('A {');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegion('B<A>', 'B'.length);
+ assertHasTarget('B<T> {');
+ }
+ {
+ assertHasRegion('A>();', 'A'.length);
+ assertHasTarget('A {');
+ }
}
- test_instanceCreation_named() {
+ test_instanceCreation_named() async {
addTestFile('''
class A {
A.named() {}
@@ -621,19 +601,18 @@
new A.named();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('A.named();', 'A'.length);
- assertHasTarget('named() {}');
- }
- {
- assertHasRegionString('named();', 'named'.length);
- assertHasTarget('named() {}');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegionString('A.named();', 'A'.length);
+ assertHasTarget('named() {}');
+ }
+ {
+ assertHasRegionString('named();', 'named'.length);
+ assertHasTarget('named() {}');
+ }
}
- test_instanceCreation_named_withTypeArgument() {
+ test_instanceCreation_named_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {
@@ -643,23 +622,22 @@
new B<A>.named();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('B<A>', 'B'.length);
- assertHasTarget('named() {}');
- }
- {
- assertHasRegion('A>.named');
- assertHasTarget('A {');
- }
- {
- assertHasRegion('named();', 'named'.length);
- assertHasTarget('named() {}');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegionString('B<A>', 'B'.length);
+ assertHasTarget('named() {}');
+ }
+ {
+ assertHasRegion('A>.named');
+ assertHasTarget('A {');
+ }
+ {
+ assertHasRegion('named();', 'named'.length);
+ assertHasTarget('named() {}');
+ }
}
- test_instanceCreation_unnamed() {
+ test_instanceCreation_unnamed() async {
addTestFile('''
class A {
A() {}
@@ -668,13 +646,12 @@
new A();
}
''');
- return prepareNavigation().then((_) {
- assertHasRegionString('A();', 'A'.length);
- assertHasTarget('A() {}', 0);
- });
+ await prepareNavigation();
+ assertHasRegionString('A();', 'A'.length);
+ assertHasTarget('A() {}', 0);
}
- test_instanceCreation_unnamed_withTypeArgument() {
+ test_instanceCreation_unnamed_withTypeArgument() async {
addTestFile('''
class A {}
class B<T> {
@@ -684,29 +661,43 @@
new B<A>();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('B<A>();', 'B'.length);
- assertHasTarget('B() {}', 0);
- }
- {
- assertHasRegion('A>();');
- assertHasTarget('A {');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegionString('B<A>();', 'B'.length);
+ assertHasTarget('B() {}', 0);
+ }
+ {
+ assertHasRegion('A>();');
+ assertHasTarget('A {');
+ }
}
- test_library() {
+ test_instanceCreation_withImportPrefix_named() async {
+ addTestFile('''
+import 'dart:async' as ppp;
+main() {
+ new ppp.Future.value(42);
+}
+''');
+ await prepareNavigation();
+ {
+ assertHasRegion('ppp.');
+ assertHasTarget('ppp;');
+ }
+ assertHasRegion('Future.value');
+ assertHasRegion('value(42)');
+ }
+
+ test_library() async {
addTestFile('''
library my.lib;
''');
- return prepareNavigation().then((_) {
- assertHasRegionString('my.lib');
- assertHasTargetString('my.lib');
- });
+ await prepareNavigation();
+ assertHasRegionString('my.lib');
+ assertHasTargetString('my.lib');
}
- test_multiplyDefinedElement() {
+ test_multiplyDefinedElement() async {
addFile('$projectPath/bin/libA.dart', 'library A; int TEST = 1;');
addFile('$projectPath/bin/libB.dart', 'library B; int TEST = 2;');
addTestFile('''
@@ -716,12 +707,11 @@
TEST;
}
''');
- return prepareNavigation().then((_) {
- assertNoRegionAt('TEST');
- });
+ await prepareNavigation();
+ assertNoRegionAt('TEST');
}
- test_operator_arithmetic() {
+ test_operator_arithmetic() async {
addTestFile('''
class A {
A operator +(other) => null;
@@ -745,22 +735,21 @@
a /= 6;
}
''');
- return prepareNavigation().then((_) {
- assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
- assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
- assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
- assertHasOperatorRegion('--a;', 2, '-(other) => null', 1);
- assertHasOperatorRegion('++a;', 2, '+(other) => null', 1);
- assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1);
- assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1);
- assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1);
- assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1);
- assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1);
- assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1);
- });
+ await prepareNavigation();
+ assertHasOperatorRegion('- 1', 1, '-(other) => null', 1);
+ assertHasOperatorRegion('+ 2', 1, '+(other) => null', 1);
+ assertHasOperatorRegion('-a; // unary', 1, '-() => null', 1);
+ assertHasOperatorRegion('--a;', 2, '-(other) => null', 1);
+ assertHasOperatorRegion('++a;', 2, '+(other) => null', 1);
+ assertHasOperatorRegion('--; // mm', 2, '-(other) => null', 1);
+ assertHasOperatorRegion('++; // pp', 2, '+(other) => null', 1);
+ assertHasOperatorRegion('-= 3', 2, '-(other) => null', 1);
+ assertHasOperatorRegion('+= 4', 2, '+(other) => null', 1);
+ assertHasOperatorRegion('*= 5', 2, '*(other) => null', 1);
+ assertHasOperatorRegion('/= 6', 2, '/(other) => null', 1);
}
- test_operator_index() {
+ test_operator_index() async {
addTestFile('''
class A {
A operator +(other) => null;
@@ -776,92 +765,106 @@
b[2] += 2;
}
''');
- return prepareNavigation().then((_) {
- assertHasOperatorRegion('[0', 1, '[](index)', 2);
- assertHasOperatorRegion('] // []', 1, '[](index)', 2);
- assertHasOperatorRegion('[1', 1, '[]=(index,', 3);
- assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
- assertHasOperatorRegion('[2', 1, '[]=(index,', 3);
- assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
- assertHasOperatorRegion('+= 2;', 2, '+(other)', 1);
- });
+ await prepareNavigation();
+ assertHasOperatorRegion('[0', 1, '[](index)', 2);
+ assertHasOperatorRegion('] // []', 1, '[](index)', 2);
+ assertHasOperatorRegion('[1', 1, '[]=(index,', 3);
+ assertHasOperatorRegion('] = 1;', 1, '[]=(index,', 3);
+ assertHasOperatorRegion('[2', 1, '[]=(index,', 3);
+ assertHasOperatorRegion('] += 2;', 1, '[]=(index,', 3);
+ assertHasOperatorRegion('+= 2;', 2, '+(other)', 1);
}
- test_partOf() {
+ test_partOf() async {
var libCode = 'library lib; part "test.dart";';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('part of lib;');
- return prepareNavigation().then((_) {
- assertHasRegionString('lib');
- assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
- });
+ await prepareNavigation();
+ assertHasRegionString('lib');
+ assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
- test_string_export() {
+ test_redirectingConstructorInvocation() async {
+ addTestFile('''
+class A {
+ A() {}
+ A.foo() : this();
+ A.bar() : this.foo();
+}
+''');
+ await prepareNavigation();
+ {
+ assertHasRegion('this();');
+ assertHasTarget('A() {}', 0);
+ }
+ {
+ assertHasRegion('this.foo');
+ assertHasTarget('foo() :');
+ }
+ {
+ assertHasRegion('foo();');
+ assertHasTarget('foo() :');
+ }
+ }
+
+ test_string_export() async {
var libCode = 'library lib;';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('export "lib.dart";');
- return prepareNavigation().then((_) {
- assertHasRegionString('"lib.dart"');
- assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
- });
+ await prepareNavigation();
+ assertHasRegionString('"lib.dart"');
+ assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
- test_string_export_unresolvedUri() {
+ test_string_export_unresolvedUri() async {
addTestFile('export "no.dart";');
- return prepareNavigation().then((_) {
- assertNoRegionString('"no.dart"');
- });
+ await prepareNavigation();
+ assertNoRegionString('"no.dart"');
}
- test_string_import() {
+ test_string_import() async {
var libCode = 'library lib;';
var libFile = addFile('$projectPath/bin/lib.dart', libCode);
addTestFile('import "lib.dart";');
- return prepareNavigation().then((_) {
- assertHasRegionString('"lib.dart"');
- assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
- });
+ await prepareNavigation();
+ assertHasRegionString('"lib.dart"');
+ assertHasFileTarget(libFile, libCode.indexOf('lib;'), 'lib'.length);
}
- test_string_import_noUri() {
+ test_string_import_noUri() async {
addTestFile('import ;');
- return prepareNavigation().then((_) {
- assertNoRegionAt('import ;');
- });
+ await prepareNavigation();
+ assertNoRegionAt('import ;');
}
- test_string_import_unresolvedUri() {
+ test_string_import_unresolvedUri() async {
addTestFile('import "no.dart";');
- return prepareNavigation().then((_) {
- assertNoRegionString('"no.dart"');
- });
+ await prepareNavigation();
+ assertNoRegionString('"no.dart"');
}
- test_string_part() {
+ test_string_part() async {
var unitCode = 'part of lib; f() {}';
var unitFile = addFile('$projectPath/bin/test_unit.dart', unitCode);
addTestFile('''
library lib;
part "test_unit.dart";
''');
- return prepareNavigation().then((_) {
- assertHasRegionString('"test_unit.dart"');
- assertHasFileTarget(unitFile, 0, 0);
- });
+ await prepareNavigation();
+ assertHasRegionString('"test_unit.dart"');
+ assertHasFileTarget(unitFile, 0, 0);
}
- test_string_part_unresolvedUri() {
+ test_string_part_unresolvedUri() async {
addTestFile('''
library lib;
part "test_unit.dart";
''');
- return prepareNavigation().then((_) {
- assertNoRegionString('"test_unit.dart"');
- });
+ await prepareNavigation();
+ assertNoRegionString('"test_unit.dart"');
}
- test_superConstructorInvocation() {
+ test_superConstructorInvocation() async {
addTestFile('''
class A {
A() {}
@@ -872,19 +875,22 @@
B.named() : super.named();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('super');
- assertHasTarget('A() {}', 0);
- }
- {
- assertHasRegionString('super.named');
- assertHasTarget('named() {}');
- }
- });
+ await prepareNavigation();
+ {
+ assertHasRegionString('super');
+ assertHasTarget('A() {}', 0);
+ }
+ {
+ assertHasRegion('super.named');
+ assertHasTarget('named() {}');
+ }
+ {
+ assertHasRegion('named();');
+ assertHasTarget('named() {}');
+ }
}
- test_superConstructorInvocation_synthetic() {
+ test_superConstructorInvocation_synthetic() async {
addTestFile('''
class A {
}
@@ -892,45 +898,39 @@
B() : super();
}
''');
- return prepareNavigation().then((_) {
- {
- assertHasRegionString('super');
- assertHasTarget('A {');
- }
- });
+ await prepareNavigation();
+ assertHasRegionString('super');
+ assertHasTarget('A {');
}
- test_targetElement() {
+ test_targetElement() async {
addTestFile('''
class AAA {}
main() {
AAA aaa = null;
}
''');
- return prepareNavigation().then((_) {
- assertHasRegionTarget('AAA aaa', 'AAA {}');
- expect(testTarget.kind, ElementKind.CLASS);
- });
+ await prepareNavigation();
+ assertHasRegionTarget('AAA aaa', 'AAA {}');
+ expect(testTarget.kind, ElementKind.CLASS);
}
- test_type_dynamic() {
+ test_type_dynamic() async {
addTestFile('''
main() {
dynamic v = null;
}
''');
- return prepareNavigation().then((_) {
- assertNoRegionAt('dynamic');
- });
+ await prepareNavigation();
+ assertNoRegionAt('dynamic');
}
- test_type_void() {
+ test_type_void() async {
addTestFile('''
void main() {
}
''');
- return prepareNavigation().then((_) {
- assertNoRegionAt('void');
- });
+ await prepareNavigation();
+ assertNoRegionAt('void');
}
}
diff --git a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
index cc7ebab..c27fa10 100644
--- a/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_occurrences_test.dart
@@ -22,14 +22,14 @@
@reflectiveTest
class AnalysisNotificationOccurrencesTest extends AbstractAnalysisTest {
List<Occurrences> occurrencesList;
- Occurrences testOccurences;
+ Occurrences testOccurrences;
/**
- * Asserts that there is an offset of [search] in [testOccurences].
+ * Asserts that there is an offset of [search] in [testOccurrences].
*/
void assertHasOffset(String search) {
int offset = findOffset(search);
- expect(testOccurences.offsets, contains(offset));
+ expect(testOccurrences.offsets, contains(offset));
}
/**
@@ -49,7 +49,7 @@
* Finds an [Occurrences] with the given [offset] and [length].
*
* If [exists] is `true`, then fails if such [Occurrences] does not exist.
- * Otherwise remembers this it into [testOccurences].
+ * Otherwise remembers this it into [testOccurrences].
*
* If [exists] is `false`, then fails if such [Occurrences] exists.
*/
@@ -64,7 +64,7 @@
fail('Not expected to find (offset=$offset; length=$length) in\n'
'${occurrencesList.join('\n')}');
}
- testOccurences = occurrences;
+ testOccurrences = occurrences;
return;
}
}
@@ -95,25 +95,23 @@
createProject();
}
- test_afterAnalysis() {
+ test_afterAnalysis() async {
addTestFile('''
main() {
var vvv = 42;
print(vvv);
}
''');
- return waitForTasksFinished().then((_) {
- return prepareOccurrences().then((_) {
- assertHasRegion('vvv =');
- expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
- expect(testOccurences.element.name, 'vvv');
- assertHasOffset('vvv = 42');
- assertHasOffset('vvv);');
- });
- });
+ await waitForTasksFinished();
+ await prepareOccurrences();
+ assertHasRegion('vvv =');
+ expect(testOccurrences.element.kind, ElementKind.LOCAL_VARIABLE);
+ expect(testOccurrences.element.name, 'vvv');
+ assertHasOffset('vvv = 42');
+ assertHasOffset('vvv);');
}
- test_field() {
+ test_field() async {
addTestFile('''
class A {
int fff;
@@ -124,26 +122,25 @@
}
}
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('fff;');
- expect(testOccurences.element.kind, ElementKind.FIELD);
- assertHasOffset('fff); // constructor');
- assertHasOffset('fff = 42;');
- assertHasOffset('fff); // print');
- });
+ await prepareOccurrences();
+ assertHasRegion('fff;');
+ expect(testOccurrences.element.kind, ElementKind.FIELD);
+ assertHasOffset('fff); // constructor');
+ assertHasOffset('fff = 42;');
+ assertHasOffset('fff); // print');
}
- test_field_unresolved() {
+ test_field_unresolved() async {
addTestFile('''
class A {
A(this.noSuchField);
}
''');
// no checks for occurrences, just ensure that there is no NPE
- return prepareOccurrences();
+ await prepareOccurrences();
}
- test_localVariable() {
+ test_localVariable() async {
addTestFile('''
main() {
var vvv = 42;
@@ -151,17 +148,16 @@
print(vvv);
}
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('vvv =');
- expect(testOccurences.element.kind, ElementKind.LOCAL_VARIABLE);
- expect(testOccurences.element.name, 'vvv');
- assertHasOffset('vvv = 42');
- assertHasOffset('vvv += 5');
- assertHasOffset('vvv);');
- });
+ await prepareOccurrences();
+ assertHasRegion('vvv =');
+ expect(testOccurrences.element.kind, ElementKind.LOCAL_VARIABLE);
+ expect(testOccurrences.element.name, 'vvv');
+ assertHasOffset('vvv = 42');
+ assertHasOffset('vvv += 5');
+ assertHasOffset('vvv);');
}
- test_memberField() {
+ test_memberField() async {
addTestFile('''
class A<T> {
T fff;
@@ -173,15 +169,14 @@
b.fff = 2;
}
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('fff;');
- expect(testOccurences.element.kind, ElementKind.FIELD);
- assertHasOffset('fff = 1;');
- assertHasOffset('fff = 2;');
- });
+ await prepareOccurrences();
+ assertHasRegion('fff;');
+ expect(testOccurrences.element.kind, ElementKind.FIELD);
+ assertHasOffset('fff = 1;');
+ assertHasOffset('fff = 2;');
}
- test_memberMethod() {
+ test_memberMethod() async {
addTestFile('''
class A<T> {
T mmm() {}
@@ -193,15 +188,14 @@
b.mmm(); // b
}
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('mmm() {}');
- expect(testOccurences.element.kind, ElementKind.METHOD);
- assertHasOffset('mmm(); // a');
- assertHasOffset('mmm(); // b');
- });
+ await prepareOccurrences();
+ assertHasRegion('mmm() {}');
+ expect(testOccurrences.element.kind, ElementKind.METHOD);
+ assertHasOffset('mmm(); // a');
+ assertHasOffset('mmm(); // b');
}
- test_topLevelVariable() {
+ test_topLevelVariable() async {
addTestFile('''
var VVV = 1;
main() {
@@ -209,15 +203,14 @@
print(VVV);
}
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('VVV = 1;');
- expect(testOccurences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
- assertHasOffset('VVV = 2;');
- assertHasOffset('VVV);');
- });
+ await prepareOccurrences();
+ assertHasRegion('VVV = 1;');
+ expect(testOccurrences.element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ assertHasOffset('VVV = 2;');
+ assertHasOffset('VVV);');
}
- test_type_class() {
+ test_type_class() async {
addTestFile('''
main() {
int a = 1;
@@ -226,18 +219,17 @@
}
int VVV = 4;
''');
- return prepareOccurrences().then((_) {
- assertHasRegion('int a');
- expect(testOccurences.element.kind, ElementKind.CLASS);
- expect(testOccurences.element.name, 'int');
- assertHasOffset('int a');
- assertHasOffset('int b');
- assertHasOffset('int c');
- assertHasOffset('int VVV');
- });
+ await prepareOccurrences();
+ assertHasRegion('int a');
+ expect(testOccurrences.element.kind, ElementKind.CLASS);
+ expect(testOccurrences.element.name, 'int');
+ assertHasOffset('int a');
+ assertHasOffset('int b');
+ assertHasOffset('int c');
+ assertHasOffset('int VVV');
}
- test_type_dynamic() {
+ test_type_dynamic() async {
addTestFile('''
main() {
dynamic a = 1;
@@ -245,20 +237,18 @@
}
dynamic V = 3;
''');
- return prepareOccurrences().then((_) {
- int offset = findOffset('dynamic a');
- findRegion(offset, 'dynamic'.length, false);
- });
+ await prepareOccurrences();
+ int offset = findOffset('dynamic a');
+ findRegion(offset, 'dynamic'.length, false);
}
- test_type_void() {
+ test_type_void() async {
addTestFile('''
void main() {
}
''');
- return prepareOccurrences().then((_) {
- int offset = findOffset('void main()');
- findRegion(offset, 'void'.length, false);
- });
+ await prepareOccurrences();
+ int offset = findOffset('void main()');
+ findRegion(offset, 'void'.length, false);
}
}
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index 679baae..1230dbc 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -47,24 +47,22 @@
createProject();
}
- test_afterAnalysis() {
+ test_afterAnalysis() async {
addTestFile('''
class AAA {
}
class BBB {
}
''');
- return waitForTasksFinished().then((_) {
- expect(outline, isNull);
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> outlines = unitOutline.children;
- expect(outlines, hasLength(2));
- });
- });
+ await waitForTasksFinished();
+ expect(outline, isNull);
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> outlines = unitOutline.children;
+ expect(outlines, hasLength(2));
}
- test_class() {
+ test_class() async {
addTestFile('''
class A<K, V> {
int fa, fb;
@@ -81,218 +79,216 @@
B(int p);
}");
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> topOutlines = unitOutline.children;
- expect(topOutlines, hasLength(2));
- // A
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> topOutlines = unitOutline.children;
+ expect(topOutlines, hasLength(2));
+ // A
+ {
+ Outline outline_A = topOutlines[0];
+ Element element_A = outline_A.element;
+ expect(element_A.kind, ElementKind.CLASS);
+ expect(element_A.name, "A");
+ expect(element_A.typeParameters, "<K, V>");
{
- Outline outline_A = topOutlines[0];
- Element element_A = outline_A.element;
- expect(element_A.kind, ElementKind.CLASS);
- expect(element_A.name, "A");
- expect(element_A.typeParameters, "<K, V>");
- {
- Location location = element_A.location;
- expect(location.offset, testCode.indexOf("A<K, V> {"));
- expect(location.length, 1);
- }
- expect(element_A.parameters, null);
- expect(element_A.returnType, null);
- // A children
- List<Outline> outlines_A = outline_A.children;
- expect(outlines_A, hasLength(10));
- {
- Outline outline = outlines_A[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fa");
- expect(element.parameters, isNull);
- expect(element.returnType, "int");
- }
- {
- Outline outline = outlines_A[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fb");
- expect(element.parameters, isNull);
- expect(element.returnType, "int");
- }
- {
- Outline outline = outlines_A[2];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fc");
- expect(element.parameters, isNull);
- expect(element.returnType, "String");
- }
- {
- Outline outline = outlines_A[3];
- Element element = outline.element;
- expect(element.kind, ElementKind.CONSTRUCTOR);
- expect(element.name, "A");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("A(int i, String s);"));
- expect(location.length, "A".length);
- }
- expect(element.parameters, "(int i, String s)");
- expect(element.returnType, isNull);
- expect(element.isAbstract, isFalse);
- expect(element.isStatic, isFalse);
- }
- {
- Outline outline = outlines_A[4];
- Element element = outline.element;
- expect(element.kind, ElementKind.CONSTRUCTOR);
- expect(element.name, "A.name");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("name(num p);"));
- expect(location.length, "name".length);
- }
- expect(element.parameters, "(num p)");
- expect(element.returnType, isNull);
- expect(element.isAbstract, isFalse);
- expect(element.isStatic, isFalse);
- }
- {
- Outline outline = outlines_A[5];
- Element element = outline.element;
- expect(element.kind, ElementKind.CONSTRUCTOR);
- expect(element.name, "A._privateName");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("_privateName(num p);"));
- expect(location.length, "_privateName".length);
- }
- expect(element.parameters, "(num p)");
- expect(element.returnType, isNull);
- expect(element.isAbstract, isFalse);
- expect(element.isStatic, isFalse);
- }
- {
- Outline outline = outlines_A[6];
- Element element = outline.element;
- expect(element.kind, ElementKind.METHOD);
- expect(element.name, "ma");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("ma(int pa) => null;"));
- expect(location.length, "ma".length);
- }
- expect(element.parameters, "(int pa)");
- expect(element.returnType, "String");
- expect(element.isAbstract, isFalse);
- expect(element.isStatic, isTrue);
- }
- {
- Outline outline = outlines_A[7];
- Element element = outline.element;
- expect(element.kind, ElementKind.METHOD);
- expect(element.name, "_mb");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("_mb(int pb);"));
- expect(location.length, "_mb".length);
- }
- expect(element.parameters, "(int pb)");
- expect(element.returnType, "");
- expect(element.isAbstract, isTrue);
- expect(element.isStatic, isFalse);
- }
- {
- Outline outline = outlines_A[8];
- Element element = outline.element;
- expect(element.kind, ElementKind.GETTER);
- expect(element.name, "propA");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("propA => null;"));
- expect(location.length, "propA".length);
- }
- expect(element.parameters, isNull);
- expect(element.returnType, "String");
- }
- {
- Outline outline = outlines_A[9];
- Element element = outline.element;
- expect(element.kind, ElementKind.SETTER);
- expect(element.name, "propB");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("propB(int v) {}"));
- expect(location.length, "propB".length);
- }
- expect(element.parameters, "(int v)");
- expect(element.returnType, "");
- }
+ Location location = element_A.location;
+ expect(location.offset, testCode.indexOf("A<K, V> {"));
+ expect(location.length, 1);
}
- // B
+ expect(element_A.parameters, null);
+ expect(element_A.returnType, null);
+ // A children
+ List<Outline> outlines_A = outline_A.children;
+ expect(outlines_A, hasLength(10));
{
- Outline outline_B = topOutlines[1];
- Element element_B = outline_B.element;
- expect(element_B.kind, ElementKind.CLASS);
- expect(element_B.name, "B");
- expect(element_B.typeParameters, isNull);
- {
- Location location = element_B.location;
- expect(location.offset, testCode.indexOf("B {"));
- expect(location.length, 1);
- }
- expect(element_B.parameters, null);
- expect(element_B.returnType, null);
- // B children
- List<Outline> outlines_B = outline_B.children;
- expect(outlines_B, hasLength(1));
- {
- Outline outline = outlines_B[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.CONSTRUCTOR);
- expect(element.name, "B");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("B(int p);"));
- expect(location.length, "B".length);
- }
- expect(element.parameters, "(int p)");
- expect(element.returnType, isNull);
- }
+ Outline outline = outlines_A[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fa");
+ expect(element.parameters, isNull);
+ expect(element.returnType, "int");
}
- });
+ {
+ Outline outline = outlines_A[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fb");
+ expect(element.parameters, isNull);
+ expect(element.returnType, "int");
+ }
+ {
+ Outline outline = outlines_A[2];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fc");
+ expect(element.parameters, isNull);
+ expect(element.returnType, "String");
+ }
+ {
+ Outline outline = outlines_A[3];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CONSTRUCTOR);
+ expect(element.name, "A");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("A(int i, String s);"));
+ expect(location.length, "A".length);
+ }
+ expect(element.parameters, "(int i, String s)");
+ expect(element.returnType, isNull);
+ expect(element.isAbstract, isFalse);
+ expect(element.isStatic, isFalse);
+ }
+ {
+ Outline outline = outlines_A[4];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CONSTRUCTOR);
+ expect(element.name, "A.name");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("name(num p);"));
+ expect(location.length, "name".length);
+ }
+ expect(element.parameters, "(num p)");
+ expect(element.returnType, isNull);
+ expect(element.isAbstract, isFalse);
+ expect(element.isStatic, isFalse);
+ }
+ {
+ Outline outline = outlines_A[5];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CONSTRUCTOR);
+ expect(element.name, "A._privateName");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("_privateName(num p);"));
+ expect(location.length, "_privateName".length);
+ }
+ expect(element.parameters, "(num p)");
+ expect(element.returnType, isNull);
+ expect(element.isAbstract, isFalse);
+ expect(element.isStatic, isFalse);
+ }
+ {
+ Outline outline = outlines_A[6];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.METHOD);
+ expect(element.name, "ma");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("ma(int pa) => null;"));
+ expect(location.length, "ma".length);
+ }
+ expect(element.parameters, "(int pa)");
+ expect(element.returnType, "String");
+ expect(element.isAbstract, isFalse);
+ expect(element.isStatic, isTrue);
+ }
+ {
+ Outline outline = outlines_A[7];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.METHOD);
+ expect(element.name, "_mb");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("_mb(int pb);"));
+ expect(location.length, "_mb".length);
+ }
+ expect(element.parameters, "(int pb)");
+ expect(element.returnType, "");
+ expect(element.isAbstract, isTrue);
+ expect(element.isStatic, isFalse);
+ }
+ {
+ Outline outline = outlines_A[8];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.GETTER);
+ expect(element.name, "propA");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("propA => null;"));
+ expect(location.length, "propA".length);
+ }
+ expect(element.parameters, isNull);
+ expect(element.returnType, "String");
+ }
+ {
+ Outline outline = outlines_A[9];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.SETTER);
+ expect(element.name, "propB");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("propB(int v) {}"));
+ expect(location.length, "propB".length);
+ }
+ expect(element.parameters, "(int v)");
+ expect(element.returnType, "");
+ }
+ }
+ // B
+ {
+ Outline outline_B = topOutlines[1];
+ Element element_B = outline_B.element;
+ expect(element_B.kind, ElementKind.CLASS);
+ expect(element_B.name, "B");
+ expect(element_B.typeParameters, isNull);
+ {
+ Location location = element_B.location;
+ expect(location.offset, testCode.indexOf("B {"));
+ expect(location.length, 1);
+ }
+ expect(element_B.parameters, null);
+ expect(element_B.returnType, null);
+ // B children
+ List<Outline> outlines_B = outline_B.children;
+ expect(outlines_B, hasLength(1));
+ {
+ Outline outline = outlines_B[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CONSTRUCTOR);
+ expect(element.name, "B");
+ {
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("B(int p);"));
+ expect(location.length, "B".length);
+ }
+ expect(element.parameters, "(int p)");
+ expect(element.returnType, isNull);
+ }
+ }
}
- test_enum() {
+ test_enum() async {
addTestFile('''
enum MyEnum {
A, B, C
}
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> topOutlines = unitOutline.children;
- expect(topOutlines, hasLength(1));
- // MyEnum
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> topOutlines = unitOutline.children;
+ expect(topOutlines, hasLength(1));
+ // MyEnum
+ {
+ Outline outline_MyEnum = topOutlines[0];
+ Element element_MyEnum = outline_MyEnum.element;
+ expect(element_MyEnum.kind, ElementKind.ENUM);
+ expect(element_MyEnum.name, "MyEnum");
{
- Outline outline_MyEnum = topOutlines[0];
- Element element_MyEnum = outline_MyEnum.element;
- expect(element_MyEnum.kind, ElementKind.ENUM);
- expect(element_MyEnum.name, "MyEnum");
- {
- Location location = element_MyEnum.location;
- expect(location.offset, testCode.indexOf("MyEnum {"));
- expect(location.length, 'MyEnum'.length);
- }
- expect(element_MyEnum.parameters, null);
- expect(element_MyEnum.returnType, null);
- // MyEnum children
- List<Outline> outlines_MyEnum = outline_MyEnum.children;
- expect(outlines_MyEnum, hasLength(3));
- _isEnumConstant(outlines_MyEnum[0], 'A');
- _isEnumConstant(outlines_MyEnum[1], 'B');
- _isEnumConstant(outlines_MyEnum[2], 'C');
+ Location location = element_MyEnum.location;
+ expect(location.offset, testCode.indexOf("MyEnum {"));
+ expect(location.length, 'MyEnum'.length);
}
- });
+ expect(element_MyEnum.parameters, null);
+ expect(element_MyEnum.returnType, null);
+ // MyEnum children
+ List<Outline> outlines_MyEnum = outline_MyEnum.children;
+ expect(outlines_MyEnum, hasLength(3));
+ _isEnumConstant(outlines_MyEnum[0], 'A');
+ _isEnumConstant(outlines_MyEnum[1], 'B');
+ _isEnumConstant(outlines_MyEnum[2], 'C');
+ }
}
/**
@@ -300,7 +296,7 @@
*
* https://code.google.com/p/dart/issues/detail?id=21373
*/
- test_invalidGetterInConstructor() {
+ test_invalidGetterInConstructor() async {
addTestFile('''
class A {
A() {
@@ -310,9 +306,8 @@
}
}
''');
- return prepareOutline().then((_) {
- expect(outline, isNotNull);
- });
+ await prepareOutline();
+ expect(outline, isNotNull);
}
test_libraryName_hasLibraryDirective() async {
@@ -352,7 +347,7 @@
expect(libraryName, isNull);
}
- test_localFunctions() {
+ test_localFunctions() async {
addTestFile('''
class A {
A() {
@@ -369,254 +364,251 @@
}
}
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> topOutlines = unitOutline.children;
- expect(topOutlines, hasLength(2));
- // A
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> topOutlines = unitOutline.children;
+ expect(topOutlines, hasLength(2));
+ // A
+ {
+ Outline outline_A = topOutlines[0];
+ Element element_A = outline_A.element;
+ expect(element_A.kind, ElementKind.CLASS);
+ expect(element_A.name, "A");
{
- Outline outline_A = topOutlines[0];
- Element element_A = outline_A.element;
- expect(element_A.kind, ElementKind.CLASS);
- expect(element_A.name, "A");
+ Location location = element_A.location;
+ expect(location.offset, testCode.indexOf("A {"));
+ expect(location.length, "A".length);
+ }
+ expect(element_A.parameters, null);
+ expect(element_A.returnType, null);
+ // A children
+ List<Outline> outlines_A = outline_A.children;
+ expect(outlines_A, hasLength(2));
+ {
+ Outline constructorOutline = outlines_A[0];
+ Element constructorElement = constructorOutline.element;
+ expect(constructorElement.kind, ElementKind.CONSTRUCTOR);
+ expect(constructorElement.name, "A");
{
- Location location = element_A.location;
- expect(location.offset, testCode.indexOf("A {"));
+ Location location = constructorElement.location;
+ expect(location.offset, testCode.indexOf("A() {"));
expect(location.length, "A".length);
}
- expect(element_A.parameters, null);
- expect(element_A.returnType, null);
- // A children
- List<Outline> outlines_A = outline_A.children;
- expect(outlines_A, hasLength(2));
+ expect(constructorElement.parameters, "()");
+ expect(constructorElement.returnType, isNull);
+ // local function
+ List<Outline> outlines_constructor = constructorOutline.children;
+ expect(outlines_constructor, hasLength(1));
{
- Outline constructorOutline = outlines_A[0];
- Element constructorElement = constructorOutline.element;
- expect(constructorElement.kind, ElementKind.CONSTRUCTOR);
- expect(constructorElement.name, "A");
+ Outline outline = outlines_constructor[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION);
+ expect(element.name, "local_A");
{
- Location location = constructorElement.location;
- expect(location.offset, testCode.indexOf("A() {"));
- expect(location.length, "A".length);
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("local_A() {}"));
+ expect(location.length, "local_A".length);
}
- expect(constructorElement.parameters, "()");
- expect(constructorElement.returnType, isNull);
- // local function
- List<Outline> outlines_constructor = constructorOutline.children;
- expect(outlines_constructor, hasLength(1));
- {
- Outline outline = outlines_constructor[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION);
- expect(element.name, "local_A");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("local_A() {}"));
- expect(location.length, "local_A".length);
- }
- expect(element.parameters, "()");
- expect(element.returnType, "int");
- }
- }
- {
- Outline outline_m = outlines_A[1];
- Element element_m = outline_m.element;
- expect(element_m.kind, ElementKind.METHOD);
- expect(element_m.name, "m");
- {
- Location location = element_m.location;
- expect(location.offset, testCode.indexOf("m() {"));
- expect(location.length, "m".length);
- }
- expect(element_m.parameters, "()");
- expect(element_m.returnType, "");
- // local function
- List<Outline> methodChildren = outline_m.children;
- expect(methodChildren, hasLength(1));
- {
- Outline outline = methodChildren[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION);
- expect(element.name, "local_m");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("local_m() {}"));
- expect(location.length, "local_m".length);
- }
- expect(element.parameters, "()");
- expect(element.returnType, "");
- }
+ expect(element.parameters, "()");
+ expect(element.returnType, "int");
}
}
- // f()
{
- Outline outline_f = topOutlines[1];
- Element element_f = outline_f.element;
- expect(element_f.kind, ElementKind.FUNCTION);
- expect(element_f.name, "f");
+ Outline outline_m = outlines_A[1];
+ Element element_m = outline_m.element;
+ expect(element_m.kind, ElementKind.METHOD);
+ expect(element_m.name, "m");
{
- Location location = element_f.location;
- expect(location.offset, testCode.indexOf("f() {"));
- expect(location.length, "f".length);
+ Location location = element_m.location;
+ expect(location.offset, testCode.indexOf("m() {"));
+ expect(location.length, "m".length);
}
- expect(element_f.parameters, "()");
- expect(element_f.returnType, "");
- // f() children
- List<Outline> outlines_f = outline_f.children;
- expect(outlines_f, hasLength(2));
+ expect(element_m.parameters, "()");
+ expect(element_m.returnType, "");
+ // local function
+ List<Outline> methodChildren = outline_m.children;
+ expect(methodChildren, hasLength(1));
{
- Outline outline_f1 = outlines_f[0];
- Element element_f1 = outline_f1.element;
- expect(element_f1.kind, ElementKind.FUNCTION);
- expect(element_f1.name, "local_f1");
+ Outline outline = methodChildren[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION);
+ expect(element.name, "local_m");
{
- Location location = element_f1.location;
- expect(location.offset, testCode.indexOf("local_f1(int i) {}"));
- expect(location.length, "local_f1".length);
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("local_m() {}"));
+ expect(location.length, "local_m".length);
}
- expect(element_f1.parameters, "(int i)");
- expect(element_f1.returnType, "");
- }
- {
- Outline outline_f2 = outlines_f[1];
- Element element_f2 = outline_f2.element;
- expect(element_f2.kind, ElementKind.FUNCTION);
- expect(element_f2.name, "local_f2");
- {
- Location location = element_f2.location;
- expect(location.offset, testCode.indexOf("local_f2(String s) {"));
- expect(location.length, "local_f2".length);
- }
- expect(element_f2.parameters, "(String s)");
- expect(element_f2.returnType, "");
- // local_f2() local function
- List<Outline> outlines_f2 = outline_f2.children;
- expect(outlines_f2, hasLength(1));
- {
- Outline outline_f21 = outlines_f2[0];
- Element element_f21 = outline_f21.element;
- expect(element_f21.kind, ElementKind.FUNCTION);
- expect(element_f21.name, "local_f21");
- {
- Location location = element_f21.location;
- expect(location.offset, testCode.indexOf("local_f21(int p) {"));
- expect(location.length, "local_f21".length);
- }
- expect(element_f21.parameters, "(int p)");
- expect(element_f21.returnType, "");
- }
+ expect(element.parameters, "()");
+ expect(element.returnType, "");
}
}
- });
+ }
+ // f()
+ {
+ Outline outline_f = topOutlines[1];
+ Element element_f = outline_f.element;
+ expect(element_f.kind, ElementKind.FUNCTION);
+ expect(element_f.name, "f");
+ {
+ Location location = element_f.location;
+ expect(location.offset, testCode.indexOf("f() {"));
+ expect(location.length, "f".length);
+ }
+ expect(element_f.parameters, "()");
+ expect(element_f.returnType, "");
+ // f() children
+ List<Outline> outlines_f = outline_f.children;
+ expect(outlines_f, hasLength(2));
+ {
+ Outline outline_f1 = outlines_f[0];
+ Element element_f1 = outline_f1.element;
+ expect(element_f1.kind, ElementKind.FUNCTION);
+ expect(element_f1.name, "local_f1");
+ {
+ Location location = element_f1.location;
+ expect(location.offset, testCode.indexOf("local_f1(int i) {}"));
+ expect(location.length, "local_f1".length);
+ }
+ expect(element_f1.parameters, "(int i)");
+ expect(element_f1.returnType, "");
+ }
+ {
+ Outline outline_f2 = outlines_f[1];
+ Element element_f2 = outline_f2.element;
+ expect(element_f2.kind, ElementKind.FUNCTION);
+ expect(element_f2.name, "local_f2");
+ {
+ Location location = element_f2.location;
+ expect(location.offset, testCode.indexOf("local_f2(String s) {"));
+ expect(location.length, "local_f2".length);
+ }
+ expect(element_f2.parameters, "(String s)");
+ expect(element_f2.returnType, "");
+ // local_f2() local function
+ List<Outline> outlines_f2 = outline_f2.children;
+ expect(outlines_f2, hasLength(1));
+ {
+ Outline outline_f21 = outlines_f2[0];
+ Element element_f21 = outline_f21.element;
+ expect(element_f21.kind, ElementKind.FUNCTION);
+ expect(element_f21.name, "local_f21");
+ {
+ Location location = element_f21.location;
+ expect(location.offset, testCode.indexOf("local_f21(int p) {"));
+ expect(location.length, "local_f21".length);
+ }
+ expect(element_f21.parameters, "(int p)");
+ expect(element_f21.returnType, "");
+ }
+ }
+ }
}
- test_sourceRange_inClass() {
+ test_sourceRange_inClass() async {
addTestFile('''
class A { // leftA
int methodA() {} // endA
int methodB() {} // endB
}
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> outlines = unitOutline.children[0].children;
- expect(outlines, hasLength(2));
- // methodA
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> outlines = unitOutline.children[0].children;
+ expect(outlines, hasLength(2));
+ // methodA
+ {
+ Outline outline = outlines[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.METHOD);
+ expect(element.name, "methodA");
{
- Outline outline = outlines[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.METHOD);
- expect(element.name, "methodA");
- {
- int offset = testCode.indexOf(" // leftA");
- int end = testCode.indexOf(" // endA");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // leftA");
+ int end = testCode.indexOf(" // endA");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // methodB
+ }
+ // methodB
+ {
+ Outline outline = outlines[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.METHOD);
+ expect(element.name, "methodB");
{
- Outline outline = outlines[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.METHOD);
- expect(element.name, "methodB");
- {
- int offset = testCode.indexOf(" // endA");
- int end = testCode.indexOf(" // endB");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // endA");
+ int end = testCode.indexOf(" // endB");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- });
+ }
}
- test_sourceRange_inClass_inVariableList() {
+ test_sourceRange_inClass_inVariableList() async {
addTestFile('''
class A { // leftA
int fieldA, fieldB, fieldC; // marker
int fieldD; // marker2
}
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> outlines = unitOutline.children[0].children;
- expect(outlines, hasLength(4));
- // fieldA
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> outlines = unitOutline.children[0].children;
+ expect(outlines, hasLength(4));
+ // fieldA
+ {
+ Outline outline = outlines[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fieldA");
{
- Outline outline = outlines[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fieldA");
- {
- int offset = testCode.indexOf(" // leftA");
- int end = testCode.indexOf(", fieldB");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // leftA");
+ int end = testCode.indexOf(", fieldB");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldB
+ }
+ // fieldB
+ {
+ Outline outline = outlines[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fieldB");
{
- Outline outline = outlines[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fieldB");
- {
- int offset = testCode.indexOf(", fieldB");
- int end = testCode.indexOf(", fieldC");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(", fieldB");
+ int end = testCode.indexOf(", fieldC");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldC
+ }
+ // fieldC
+ {
+ Outline outline = outlines[2];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fieldC");
{
- Outline outline = outlines[2];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fieldC");
- {
- int offset = testCode.indexOf(", fieldC");
- int end = testCode.indexOf(" // marker");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(", fieldC");
+ int end = testCode.indexOf(" // marker");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldD
+ }
+ // fieldD
+ {
+ Outline outline = outlines[3];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FIELD);
+ expect(element.name, "fieldD");
{
- Outline outline = outlines[3];
- Element element = outline.element;
- expect(element.kind, ElementKind.FIELD);
- expect(element.name, "fieldD");
- {
- int offset = testCode.indexOf(" // marker");
- int end = testCode.indexOf(" // marker2");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // marker");
+ int end = testCode.indexOf(" // marker2");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- });
+ }
}
- test_sourceRange_inUnit() {
+ test_sourceRange_inUnit() async {
addTestFile('''
library lib;
/// My first class.
@@ -625,104 +617,102 @@
class B {
} // endB
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> topOutlines = unitOutline.children;
- expect(topOutlines, hasLength(2));
- // A
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> topOutlines = unitOutline.children;
+ expect(topOutlines, hasLength(2));
+ // A
+ {
+ Outline outline = topOutlines[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CLASS);
+ expect(element.name, "A");
{
- Outline outline = topOutlines[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.CLASS);
- expect(element.name, "A");
- {
- int offset = testCode.indexOf("/// My first class.");
- int end = testCode.indexOf(" // endA");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf("/// My first class.");
+ int end = testCode.indexOf(" // endA");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // B
+ }
+ // B
+ {
+ Outline outline = topOutlines[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CLASS);
+ expect(element.name, "B");
{
- Outline outline = topOutlines[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.CLASS);
- expect(element.name, "B");
- {
- int offset = testCode.indexOf(" // endA");
- int end = testCode.indexOf(" // endB");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // endA");
+ int end = testCode.indexOf(" // endB");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- });
+ }
}
- test_sourceRange_inUnit_inVariableList() {
+ test_sourceRange_inUnit_inVariableList() async {
addTestFile('''
int fieldA, fieldB, fieldC; // marker
int fieldD; // marker2
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> outlines = unitOutline.children;
- expect(outlines, hasLength(4));
- // fieldA
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> outlines = unitOutline.children;
+ expect(outlines, hasLength(4));
+ // fieldA
+ {
+ Outline outline = outlines[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ expect(element.name, "fieldA");
{
- Outline outline = outlines[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
- expect(element.name, "fieldA");
- {
- int offset = 0;
- int end = testCode.indexOf(", fieldB");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = 0;
+ int end = testCode.indexOf(", fieldB");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldB
+ }
+ // fieldB
+ {
+ Outline outline = outlines[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ expect(element.name, "fieldB");
{
- Outline outline = outlines[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
- expect(element.name, "fieldB");
- {
- int offset = testCode.indexOf(", fieldB");
- int end = testCode.indexOf(", fieldC");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(", fieldB");
+ int end = testCode.indexOf(", fieldC");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldC
+ }
+ // fieldC
+ {
+ Outline outline = outlines[2];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ expect(element.name, "fieldC");
{
- Outline outline = outlines[2];
- Element element = outline.element;
- expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
- expect(element.name, "fieldC");
- {
- int offset = testCode.indexOf(", fieldC");
- int end = testCode.indexOf(" // marker");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(", fieldC");
+ int end = testCode.indexOf(" // marker");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- // fieldD
+ }
+ // fieldD
+ {
+ Outline outline = outlines[3];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
+ expect(element.name, "fieldD");
{
- Outline outline = outlines[3];
- Element element = outline.element;
- expect(element.kind, ElementKind.TOP_LEVEL_VARIABLE);
- expect(element.name, "fieldD");
- {
- int offset = testCode.indexOf(" // marker");
- int end = testCode.indexOf(" // marker2");
- expect(outline.offset, offset);
- expect(outline.length, end - offset);
- }
+ int offset = testCode.indexOf(" // marker");
+ int end = testCode.indexOf(" // marker2");
+ expect(outline.offset, offset);
+ expect(outline.length, end - offset);
}
- });
+ }
}
- test_topLevel() {
+ test_topLevel() async {
addTestFile('''
typedef String FTA<K, V>(int i, String s);
typedef FTB(int p);
@@ -735,121 +725,120 @@
String get propA => null;
set propB(int v) {}
''');
- return prepareOutline().then((_) {
- Outline unitOutline = outline;
- List<Outline> topOutlines = unitOutline.children;
- expect(topOutlines, hasLength(10));
- // FTA
+ await prepareOutline();
+ Outline unitOutline = outline;
+ List<Outline> topOutlines = unitOutline.children;
+ expect(topOutlines, hasLength(10));
+ // FTA
+ {
+ Outline outline = topOutlines[0];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
+ expect(element.name, "FTA");
+ expect(element.typeParameters, "<K, V>");
{
- Outline outline = topOutlines[0];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
- expect(element.name, "FTA");
- expect(element.typeParameters, "<K, V>");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("FTA<K, V>("));
- expect(location.length, "FTA".length);
- }
- expect(element.parameters, "(int i, String s)");
- expect(element.returnType, "String");
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("FTA<K, V>("));
+ expect(location.length, "FTA".length);
}
- // FTB
+ expect(element.parameters, "(int i, String s)");
+ expect(element.returnType, "String");
+ }
+ // FTB
+ {
+ Outline outline = topOutlines[1];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
+ expect(element.name, "FTB");
+ expect(element.typeParameters, isNull);
{
- Outline outline = topOutlines[1];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION_TYPE_ALIAS);
- expect(element.name, "FTB");
- expect(element.typeParameters, isNull);
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("FTB("));
- expect(location.length, "FTB".length);
- }
- expect(element.parameters, "(int p)");
- expect(element.returnType, "");
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("FTB("));
+ expect(location.length, "FTB".length);
}
- // CTA
+ expect(element.parameters, "(int p)");
+ expect(element.returnType, "");
+ }
+ // CTA
+ {
+ Outline outline = topOutlines[4];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
+ expect(element.name, "CTA");
+ expect(element.typeParameters, '<T>');
{
- Outline outline = topOutlines[4];
- Element element = outline.element;
- expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
- expect(element.name, "CTA");
- expect(element.typeParameters, '<T>');
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("CTA<T> ="));
- expect(location.length, "CTA".length);
- }
- expect(element.parameters, isNull);
- expect(element.returnType, isNull);
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("CTA<T> ="));
+ expect(location.length, "CTA".length);
}
- // CTB
+ expect(element.parameters, isNull);
+ expect(element.returnType, isNull);
+ }
+ // CTB
+ {
+ Outline outline = topOutlines[5];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
+ expect(element.name, 'CTB');
+ expect(element.typeParameters, isNull);
+ expect(element.returnType, isNull);
+ }
+ // fA
+ {
+ Outline outline = topOutlines[6];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION);
+ expect(element.name, "fA");
{
- Outline outline = topOutlines[5];
- Element element = outline.element;
- expect(element.kind, ElementKind.CLASS_TYPE_ALIAS);
- expect(element.name, 'CTB');
- expect(element.typeParameters, isNull);
- expect(element.returnType, isNull);
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("fA("));
+ expect(location.length, "fA".length);
}
- // fA
+ expect(element.parameters, "(int i, String s)");
+ expect(element.returnType, "String");
+ }
+ // fB
+ {
+ Outline outline = topOutlines[7];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.FUNCTION);
+ expect(element.name, "fB");
{
- Outline outline = topOutlines[6];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION);
- expect(element.name, "fA");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("fA("));
- expect(location.length, "fA".length);
- }
- expect(element.parameters, "(int i, String s)");
- expect(element.returnType, "String");
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("fB("));
+ expect(location.length, "fB".length);
}
- // fB
+ expect(element.parameters, "(int p)");
+ expect(element.returnType, "");
+ }
+ // propA
+ {
+ Outline outline = topOutlines[8];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.GETTER);
+ expect(element.name, "propA");
{
- Outline outline = topOutlines[7];
- Element element = outline.element;
- expect(element.kind, ElementKind.FUNCTION);
- expect(element.name, "fB");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("fB("));
- expect(location.length, "fB".length);
- }
- expect(element.parameters, "(int p)");
- expect(element.returnType, "");
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("propA => null;"));
+ expect(location.length, "propA".length);
}
- // propA
+ expect(element.parameters, "");
+ expect(element.returnType, "String");
+ }
+ // propB
+ {
+ Outline outline = topOutlines[9];
+ Element element = outline.element;
+ expect(element.kind, ElementKind.SETTER);
+ expect(element.name, "propB");
{
- Outline outline = topOutlines[8];
- Element element = outline.element;
- expect(element.kind, ElementKind.GETTER);
- expect(element.name, "propA");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("propA => null;"));
- expect(location.length, "propA".length);
- }
- expect(element.parameters, "");
- expect(element.returnType, "String");
+ Location location = element.location;
+ expect(location.offset, testCode.indexOf("propB(int v) {}"));
+ expect(location.length, "propB".length);
}
- // propB
- {
- Outline outline = topOutlines[9];
- Element element = outline.element;
- expect(element.kind, ElementKind.SETTER);
- expect(element.name, "propB");
- {
- Location location = element.location;
- expect(location.offset, testCode.indexOf("propB(int v) {}"));
- expect(location.length, "propB".length);
- }
- expect(element.parameters, "(int v)");
- expect(element.returnType, "");
- }
- });
+ expect(element.parameters, "(int v)");
+ expect(element.returnType, "");
+ }
}
void _isEnumConstant(Outline outline, String name) {
diff --git a/pkg/analysis_server/test/analysis/notification_overrides_test.dart b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
index fa1a0b5..2465be3 100644
--- a/pkg/analysis_server/test/analysis/notification_overrides_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_overrides_test.dart
@@ -121,7 +121,7 @@
createProject();
}
- test_afterAnalysis() {
+ test_afterAnalysis() async {
addTestFile('''
class A {
m() {} // in A
@@ -130,16 +130,14 @@
m() {} // in B
}
''');
- return waitForTasksFinished().then((_) {
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in B');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in A');
- });
- });
+ await waitForTasksFinished();
+ await prepareOverrides();
+ assertHasOverride('m() {} // in B');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
}
- test_definedInInterface_ofInterface() {
+ test_definedInInterface_ofInterface() async {
addTestFile('''
class A {
m() {} // in A
@@ -149,14 +147,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in A');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
}
- test_definedInInterface_ofSuper() {
+ test_definedInInterface_ofSuper() async {
addTestFile('''
class A {
m() {} // in A
@@ -166,14 +163,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in A');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
}
- test_interface_method_direct_multiple() {
+ test_interface_method_direct_multiple() async {
addTestFile('''
class IA {
m() {} // in IA
@@ -185,15 +181,14 @@
m() {} // in A
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in A');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in IA');
- assertHasInterfaceMember('m() {} // in IB');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in A');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in IA');
+ assertHasInterfaceMember('m() {} // in IB');
}
- test_interface_method_direct_single() {
+ test_interface_method_direct_single() async {
addTestFile('''
class A {
m() {} // in A
@@ -202,14 +197,13 @@
m() {} // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in B');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in A');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in B');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
}
- test_interface_method_indirect_single() {
+ test_interface_method_indirect_single() async {
addTestFile('''
class A {
m() {} // in A
@@ -220,14 +214,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- assertNoSuperMember();
- assertHasInterfaceMember('m() {} // in A');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ assertNoSuperMember();
+ assertHasInterfaceMember('m() {} // in A');
}
- test_interface_stopWhenFound() {
+ test_interface_stopWhenFound() async {
addTestFile('''
class A {
m() {} // in A
@@ -239,14 +232,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- expect(override.interfaceMembers, hasLength(1));
- assertHasInterfaceMember('m() {} // in B');
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ expect(override.interfaceMembers, hasLength(1));
+ assertHasInterfaceMember('m() {} // in B');
}
- test_mix_sameMethod() {
+ test_mix_sameMethod() async {
addTestFile('''
class A {
m() {} // in A
@@ -257,14 +249,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- assertHasSuperElement('m() {} // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ assertHasSuperElement('m() {} // in A');
+ assertNoInterfaceMembers();
}
- test_mix_sameMethod_Object_hashCode() {
+ test_mix_sameMethod_Object_hashCode() async {
addTestFile('''
class A {}
abstract class B {}
@@ -272,14 +263,13 @@
int get hashCode => 42;
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('hashCode => 42;');
- expect(override.superclassMember, isNotNull);
- expect(override.interfaceMembers, isNull);
- });
+ await prepareOverrides();
+ assertHasOverride('hashCode => 42;');
+ expect(override.superclassMember, isNotNull);
+ expect(override.interfaceMembers, isNull);
}
- test_staticMembers() {
+ test_staticMembers() async {
addTestFile('''
class A {
static int F = 0;
@@ -294,12 +284,11 @@
static void set S(int v) {}
}
''');
- return prepareOverrides().then((_) {
- expect(overridesList, isEmpty);
- });
+ await prepareOverrides();
+ expect(overridesList, isEmpty);
}
- test_super_fieldByField() {
+ test_super_fieldByField() async {
addTestFile('''
class A {
int fff; // in A
@@ -308,14 +297,13 @@
int fff; // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff; // in B');
- assertHasSuperElement('fff; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff; // in B');
+ assertHasSuperElement('fff; // in A');
+ assertNoInterfaceMembers();
}
- test_super_fieldByGetter() {
+ test_super_fieldByGetter() async {
addTestFile('''
class A {
int fff; // in A
@@ -324,14 +312,13 @@
get fff => 0; // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff => 0; // in B');
- assertHasSuperElement('fff; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff => 0; // in B');
+ assertHasSuperElement('fff; // in A');
+ assertNoInterfaceMembers();
}
- test_super_fieldByMethod() {
+ test_super_fieldByMethod() async {
addTestFile('''
class A {
int fff; // in A
@@ -340,14 +327,13 @@
fff() {} // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff() {} // in B');
- assertHasSuperElement('fff; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff() {} // in B');
+ assertHasSuperElement('fff; // in A');
+ assertNoInterfaceMembers();
}
- test_super_fieldBySetter() {
+ test_super_fieldBySetter() async {
addTestFile('''
class A {
int fff; // in A
@@ -356,14 +342,13 @@
set fff(x) {} // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff(x) {} // in B');
- assertHasSuperElement('fff; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff(x) {} // in B');
+ assertHasSuperElement('fff; // in A');
+ assertNoInterfaceMembers();
}
- test_super_getterByField() {
+ test_super_getterByField() async {
addTestFile('''
class A {
get fff => 0; // in A
@@ -373,14 +358,13 @@
int fff; // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff; // in B');
- assertHasSuperElement('fff => 0; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff; // in B');
+ assertHasSuperElement('fff => 0; // in A');
+ assertNoInterfaceMembers();
}
- test_super_getterByGetter() {
+ test_super_getterByGetter() async {
addTestFile('''
class A {
get fff => 0; // in A
@@ -389,14 +373,13 @@
get fff => 0; // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff => 0; // in B');
- assertHasSuperElement('fff => 0; // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff => 0; // in B');
+ assertHasSuperElement('fff => 0; // in A');
+ assertNoInterfaceMembers();
}
- test_super_method_direct() {
+ test_super_method_direct() async {
addTestFile('''
class A {
m() {} // in A
@@ -405,14 +388,13 @@
m() {} // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in B');
- assertHasSuperElement('m() {} // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in B');
+ assertHasSuperElement('m() {} // in A');
+ assertNoInterfaceMembers();
}
- test_super_method_indirect() {
+ test_super_method_indirect() async {
addTestFile('''
class A {
m() {} // in A
@@ -423,14 +405,13 @@
m() {} // in C
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('m() {} // in C');
- assertHasSuperElement('m() {} // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('m() {} // in C');
+ assertHasSuperElement('m() {} // in A');
+ assertNoInterfaceMembers();
}
- test_super_method_superTypeCycle() {
+ test_super_method_superTypeCycle() async {
addTestFile('''
class A extends B {
m() {} // in A
@@ -439,12 +420,11 @@
m() {} // in B
}
''');
- return prepareOverrides().then((_) {
- // must finish
- });
+ await prepareOverrides();
+ // must finish
}
- test_super_setterBySetter() {
+ test_super_setterBySetter() async {
addTestFile('''
class A {
set fff(x) {} // in A
@@ -453,10 +433,9 @@
set fff(x) {} // in B
}
''');
- return prepareOverrides().then((_) {
- assertHasOverride('fff(x) {} // in B');
- assertHasSuperElement('fff(x) {} // in A');
- assertNoInterfaceMembers();
- });
+ await prepareOverrides();
+ assertHasOverride('fff(x) {} // in B');
+ assertHasSuperElement('fff(x) {} // in A');
+ assertNoInterfaceMembers();
}
}
diff --git a/pkg/analysis_server/test/analysis/reanalyze_test.dart b/pkg/analysis_server/test/analysis/reanalyze_test.dart
index 310e6d7..0b39e88 100644
--- a/pkg/analysis_server/test/analysis/reanalyze_test.dart
+++ b/pkg/analysis_server/test/analysis/reanalyze_test.dart
@@ -44,31 +44,32 @@
expect(newContext, isNot(same(oldContext)));
}
- test_reanalyze_with_overlay() {
+ test_reanalyze_with_overlay() async {
createProject();
resourceProvider.newFolder(testFolder);
resourceProvider.newFile(testFile, 'main() {}');
- return waitForTasksFinished().then((_) {
- // Update the content with an overlay that contains a syntax error.
- server.updateContent('1', {testFile: new AddContentOverlay('main() {')});
- return waitForTasksFinished();
- }).then((_) {
- // Verify that the syntax error was detected.
+ await waitForTasksFinished();
+ // Update the content with an overlay that contains a syntax error.
+ server.updateContent('1', {testFile: new AddContentOverlay('main() {')});
+ await waitForTasksFinished();
+ // Verify that the syntax error was detected.
+ {
List<AnalysisError> errors = filesErrors[testFile];
expect(errors, hasLength(1));
- // Remove testFile from filesErrors so that we'll notice when the file is
- // re-analyzed.
- filesErrors.remove(testFile);
- // Reanalyze.
- server.reanalyze(null);
- return waitForTasksFinished();
- }).then((_) {
- // The file should have been reanalyzed.
- expect(filesErrors, contains(testFile));
- // Verify that the syntax error is present (this indicates that the
- // content introduced by the call to updateContent is still in effect).
+ }
+ // Remove testFile from filesErrors so that we'll notice when the file is
+ // re-analyzed.
+ filesErrors.remove(testFile);
+ // Reanalyze.
+ server.reanalyze(null);
+ await waitForTasksFinished();
+ // The file should have been reanalyzed.
+ expect(filesErrors, contains(testFile));
+ // Verify that the syntax error is present (this indicates that the
+ // content introduced by the call to updateContent is still in effect).
+ {
List<AnalysisError> errors = filesErrors[testFile];
expect(errors, hasLength(1));
- });
+ }
}
}
diff --git a/pkg/analysis_server/test/analysis/set_priority_files_test.dart b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
index 770a036..f89ba30 100644
--- a/pkg/analysis_server/test/analysis/set_priority_files_test.dart
+++ b/pkg/analysis_server/test/analysis/set_priority_files_test.dart
@@ -72,6 +72,58 @@
expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
}
+ test_ignoredInAnalysisOptions() async {
+ String sampleFile = '$projectPath/samples/sample.dart';
+ addFile(
+ '$projectPath/.analysis_options',
+ r'''
+analyzer:
+ exclude:
+ - 'samples/**'
+''');
+ addFile(sampleFile, '');
+ // attempt to set priority file
+ Response response = await _setPriorityFile(sampleFile);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+ }
+
+ test_ignoredInAnalysisOptions_inChildContext() async {
+ addFile('$projectPath/.packages', '');
+ addFile('$projectPath/child/.packages', '');
+ String sampleFile = '$projectPath/child/samples/sample.dart';
+ addFile(
+ '$projectPath/child/.analysis_options',
+ r'''
+analyzer:
+ exclude:
+ - 'samples/**'
+''');
+ addFile(sampleFile, '');
+ // attempt to set priority file
+ Response response = await _setPriorityFile(sampleFile);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+ }
+
+ test_ignoredInAnalysisOptions_inRootContext() async {
+ addFile('$projectPath/.packages', '');
+ addFile('$projectPath/child/.packages', '');
+ String sampleFile = '$projectPath/child/samples/sample.dart';
+ addFile(
+ '$projectPath/.analysis_options',
+ r'''
+analyzer:
+ exclude:
+ - 'child/samples/**'
+''');
+ addFile(sampleFile, '');
+ // attempt to set priority file
+ Response response = await _setPriorityFile(sampleFile);
+ expect(response.error, isNotNull);
+ expect(response.error.code, RequestErrorCode.UNANALYZED_PRIORITY_FILES);
+ }
+
_setPriorityFile(String file) async {
Request request =
new AnalysisSetPriorityFilesParams(<String>[file]).toRequest('0');
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index c367665..de27610 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -12,6 +12,7 @@
import 'package:analysis_server/src/domain_analysis.dart';
import 'package:analysis_server/src/plugin/linter_plugin.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_plugin.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
@@ -101,7 +102,8 @@
List<Plugin> plugins = <Plugin>[
serverPlugin,
linterPlugin,
- linterServerPlugin
+ linterServerPlugin,
+ dartCompletionPlugin,
];
// Accessing `taskManager` ensures that AE plugins are registered.
AnalysisEngine.instance.taskManager;
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 5275d3a..58179eb 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -323,7 +323,7 @@
subscriptions[service] = <String>[bar.path].toSet();
}
server.setAnalysisSubscriptions(subscriptions);
- await pumpEventQueue(500);
+ await pumpEventQueue(1000);
expect(server.statusAnalyzing, isFalse);
channel.notificationsReceived.clear();
server.updateContent(
@@ -456,6 +456,27 @@
});
}
+ test_setAnalysisSubscriptions_fileInIgnoredFolder() async {
+ String path = '/project/samples/sample.dart';
+ resourceProvider.newFile(path, '');
+ resourceProvider.newFile(
+ '/project/.analysis_options',
+ r'''
+analyzer:
+ exclude:
+ - 'samples/**'
+''');
+ server.setAnalysisRoots('0', ['/project'], [], {});
+ server.setAnalysisSubscriptions(<AnalysisService, Set<String>>{
+ AnalysisService.NAVIGATION: new Set<String>.from([path])
+ });
+ // the file is excluded, so no navigation notification
+ await server.onAnalysisComplete;
+ expect(channel.notificationsReceived.any((notification) {
+ return notification.event == ANALYSIS_NAVIGATION;
+ }), isFalse);
+ }
+
Future test_shutdown() {
server.handlers = [new ServerDomainHandler(server)];
var request = new Request('my28', SERVER_SHUTDOWN);
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 7fc8d23..0d5ea53 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -1121,9 +1121,8 @@
buildTests(
'testCompletion_combinator_afterComma',
'''
-"import 'dart:math' show cos, !1;''',
- <String>["1+PI", "1+sin", "1+Random", "1-String"],
- failingTests: '1');
+import 'dart:math' show cos, !1;''',
+ <String>["1+PI", "1+sin", "1+Random", "1-String"]);
buildTests(
'testCompletion_combinator_ended',
@@ -2119,7 +2118,7 @@
sources.clear();
sources["/lib.dart"] = '''
library lib
-class _A
+class _A
foo() {}
class A extends _A {
@@ -2851,7 +2850,7 @@
// test analysis of untyped fields and top-level vars
buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''',
- <String>["1+length"], failingTests: '1');
+ <String>["1+length"]);
// TODO(scheglov) decide what to do with Type for untyped field (not
// supported by the new store)
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index dd3961c..9f51368 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -93,6 +93,51 @@
resourceProvider.newFolder(projPath);
}
+ test_analysis_options_parse_failure() async {
+ // Create files.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile([libPath, 'main.dart']);
+ String sdkExtPath = newFolder([projPath, 'sdk_ext']);
+ newFile([sdkExtPath, 'entry.dart']);
+ String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
+ newFile([sdkExtSrcPath, 'part.dart']);
+ // Setup analysis options file with ignore list.
+ newFile(
+ [projPath, '.analysis_options'],
+ r'''
+;
+''');
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+
+ // No error means success.
+ }
+
+ void test_contextsInAnalysisRoot_nestedContext() {
+ String subProjPath = posix.join(projPath, 'subproj');
+ Folder subProjFolder = resourceProvider.newFolder(subProjPath);
+ resourceProvider.newFile(
+ posix.join(subProjPath, 'pubspec.yaml'), 'contents');
+ String subProjFilePath = posix.join(subProjPath, 'file.dart');
+ resourceProvider.newFile(subProjFilePath, 'contents');
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ // Make sure that there really are contexts for both the main project and
+ // the subproject.
+ Folder projFolder = resourceProvider.getFolder(projPath);
+ ContextInfo projContextInfo = manager.getContextInfoFor(projFolder);
+ expect(projContextInfo, isNotNull);
+ expect(projContextInfo.folder, projFolder);
+ ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
+ expect(subProjContextInfo, isNotNull);
+ expect(subProjContextInfo.folder, subProjFolder);
+ expect(projContextInfo.context != subProjContextInfo.context, isTrue);
+ // Check that contextsInAnalysisRoot() works.
+ List<AnalysisContext> contexts = manager.contextsInAnalysisRoot(projFolder);
+ expect(contexts, hasLength(2));
+ expect(contexts, contains(projContextInfo.context));
+ expect(contexts, contains(subProjContextInfo.context));
+ }
+
test_embedder_options() async {
// Create files.
String libPath = newFolder([projPath, LIB_NAME]);
@@ -167,51 +212,6 @@
expect(source.fullName, '/my/proj/sdk_ext/entry.dart');
}
- test_analysis_options_parse_failure() async {
- // Create files.
- String libPath = newFolder([projPath, LIB_NAME]);
- newFile([libPath, 'main.dart']);
- String sdkExtPath = newFolder([projPath, 'sdk_ext']);
- newFile([sdkExtPath, 'entry.dart']);
- String sdkExtSrcPath = newFolder([projPath, 'sdk_ext', 'src']);
- newFile([sdkExtSrcPath, 'part.dart']);
- // Setup analysis options file with ignore list.
- newFile(
- [projPath, '.analysis_options'],
- r'''
-;
-''');
- // Setup context.
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
-
- // No error means success.
- }
-
- void test_contextsInAnalysisRoot_nestedContext() {
- String subProjPath = posix.join(projPath, 'subproj');
- Folder subProjFolder = resourceProvider.newFolder(subProjPath);
- resourceProvider.newFile(
- posix.join(subProjPath, 'pubspec.yaml'), 'contents');
- String subProjFilePath = posix.join(subProjPath, 'file.dart');
- resourceProvider.newFile(subProjFilePath, 'contents');
- manager.setRoots(<String>[projPath], <String>[], <String, String>{});
- // Make sure that there really are contexts for both the main project and
- // the subproject.
- Folder projFolder = resourceProvider.getFolder(projPath);
- ContextInfo projContextInfo = manager.getContextInfoFor(projFolder);
- expect(projContextInfo, isNotNull);
- expect(projContextInfo.folder, projFolder);
- ContextInfo subProjContextInfo = manager.getContextInfoFor(subProjFolder);
- expect(subProjContextInfo, isNotNull);
- expect(subProjContextInfo.folder, subProjFolder);
- expect(projContextInfo.context != subProjContextInfo.context, isTrue);
- // Check that contextsInAnalysisRoot() works.
- List<AnalysisContext> contexts = manager.contextsInAnalysisRoot(projFolder);
- expect(contexts, hasLength(2));
- expect(contexts, contains(projContextInfo.context));
- expect(contexts, contains(subProjContextInfo.context));
- }
-
test_embedder_packagespec() async {
// Create files.
String libPath = newFolder([projPath, LIB_NAME]);
@@ -1143,6 +1143,158 @@
callbacks.assertContextFiles(project, [fileA, fileB]);
}
+ void test_setRoots_nested_excludedByOuter() {
+ String project = '/project';
+ String projectPubspec = '$project/pubspec.yaml';
+ String example = '$project/example';
+ String examplePubspec = '$example/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(projectPubspec, 'name: project');
+ resourceProvider.newFile(examplePubspec, 'name: example');
+ newFile(
+ [project, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
+ r'''
+analyzer:
+ exclude:
+ - 'example'
+''');
+ manager.setRoots(
+ <String>[project, example], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo projectInfo = rootInfo.children[0];
+ expect(projectInfo.folder.path, project);
+ expect(projectInfo.children, hasLength(1));
+ {
+ ContextInfo exampleInfo = projectInfo.children[0];
+ expect(exampleInfo.folder.path, example);
+ expect(exampleInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
+ }
+
+ void test_setRoots_nested_excludedByOuter_deep() {
+ String a = '/a';
+ String c = '$a/b/c';
+ String aPubspec = '$a/pubspec.yaml';
+ String cPubspec = '$c/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(aPubspec, 'name: aaa');
+ resourceProvider.newFile(cPubspec, 'name: ccc');
+ newFile(
+ [a, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
+ r'''
+analyzer:
+ exclude:
+ - 'b**'
+''');
+ manager.setRoots(<String>[a, c], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo aInfo = rootInfo.children[0];
+ expect(aInfo.folder.path, a);
+ expect(aInfo.children, hasLength(1));
+ {
+ ContextInfo cInfo = aInfo.children[0];
+ expect(cInfo.folder.path, c);
+ expect(cInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([a, c]));
+ }
+
+ void test_setRoots_nested_includedByOuter_innerFirst() {
+ String project = '/project';
+ String projectPubspec = '$project/pubspec.yaml';
+ String example = '$project/example';
+ String examplePubspec = '$example/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(projectPubspec, 'name: project');
+ resourceProvider.newFile(examplePubspec, 'name: example');
+ manager.setRoots(
+ <String>[example, project], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo projectInfo = rootInfo.children[0];
+ expect(projectInfo.folder.path, project);
+ expect(projectInfo.children, hasLength(1));
+ {
+ ContextInfo exampleInfo = projectInfo.children[0];
+ expect(exampleInfo.folder.path, example);
+ expect(exampleInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
+ }
+
+ void test_setRoots_nested_includedByOuter_outerPubspec() {
+ String project = '/project';
+ String projectPubspec = '$project/pubspec.yaml';
+ String example = '$project/example';
+ // create files
+ resourceProvider.newFile(projectPubspec, 'name: project');
+ resourceProvider.newFolder(example);
+ manager.setRoots(
+ <String>[project, example], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo projectInfo = rootInfo.children[0];
+ expect(projectInfo.folder.path, project);
+ expect(projectInfo.children, isEmpty);
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(1));
+ expect(callbacks.currentContextPaths, unorderedEquals([project]));
+ }
+
+ void test_setRoots_nested_includedByOuter_twoPubspecs() {
+ String project = '/project';
+ String projectPubspec = '$project/pubspec.yaml';
+ String example = '$project/example';
+ String examplePubspec = '$example/pubspec.yaml';
+ // create files
+ resourceProvider.newFile(projectPubspec, 'name: project');
+ resourceProvider.newFile(examplePubspec, 'name: example');
+ manager.setRoots(
+ <String>[project, example], <String>[], <String, String>{});
+ // verify
+ {
+ ContextInfo rootInfo = manager.rootInfo;
+ expect(rootInfo.children, hasLength(1));
+ {
+ ContextInfo projectInfo = rootInfo.children[0];
+ expect(projectInfo.folder.path, project);
+ expect(projectInfo.children, hasLength(1));
+ {
+ ContextInfo exampleInfo = projectInfo.children[0];
+ expect(exampleInfo.folder.path, example);
+ expect(exampleInfo.children, isEmpty);
+ }
+ }
+ }
+ expect(callbacks.currentContextPaths, hasLength(2));
+ expect(callbacks.currentContextPaths, unorderedEquals([project, example]));
+ }
+
void test_setRoots_newFolderWithPackageRoot() {
String packageRootPath = '/package';
manager.setRoots(<String>[projPath], <String>[],
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 640d2fd..2c6fc7b 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -55,6 +55,46 @@
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) {
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 6c4b295..888b7cc 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -16,10 +16,8 @@
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart'
show AnalysisRequest, CompletionRequest, CompletionResult;
-import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
- as newApi;
import 'package:analysis_server/src/services/completion/completion_manager.dart';
-import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
+import 'package:analysis_server/src/services/completion/dart/contribution_sorter.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/index/index.dart' show Index;
import 'package:analysis_server/src/services/index/local_memory_index.dart';
@@ -30,9 +28,6 @@
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/dart.dart';
-import 'package:analyzer/task/model.dart';
import 'package:plugin/manager.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -363,6 +358,8 @@
expect(suggestionsDone, isNotNull);
suggestions = params.results;
}
+ } else if (notification.event == SERVER_ERROR) {
+ fail('server error: ${notification.toJson()}');
}
}
@@ -620,28 +617,6 @@
});
}
- test_relevancy_sorter_analysis() {
- var originalSorter = DartCompletionManager.defaultContributionSorter;
-
- // Setup the mock sorter to request additional analysis
- var mockSorter = new MockRelevancySorter();
- mockSorter.addTask(PARSED_UNIT);
- mockSorter.addTask(LIBRARY_ELEMENT1);
- mockSorter.addTask(RESOLVED_UNIT3);
- mockSorter.addTask(RESOLVED_UNIT3);
-
- DartCompletionManager.defaultContributionSorter = mockSorter;
- addTestFile('main() {Map m; m.^}');
-
- return getSuggestions().then((_) {
- DartCompletionManager.defaultContributionSorter = originalSorter;
- mockSorter.enabled = false;
-
- // Assert that the analysis requests were processed
- mockSorter.assertAnalysisRequestsProcessed();
- });
- }
-
test_simple() {
addTestFile('''
void main() {
@@ -747,38 +722,16 @@
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
-class MockRelevancySorter implements ContributionSorter {
+class MockRelevancySorter implements DartContributionSorter {
bool enabled = true;
- List<ResultDescriptor> descriptors = <ResultDescriptor>[];
-
- void addTask(ResultDescriptor descriptor) {
- descriptors.add(descriptor);
- }
-
- void assertAnalysisRequestsProcessed() {
- expect(descriptors, hasLength(0));
- }
@override
- AnalysisRequest sort(
+ Future sort(
CompletionRequest request, Iterable<CompletionSuggestion> suggestions) {
if (!enabled) {
throw 'unexpected sort';
}
- return _nextAnalysisRequest(request);
- }
-
- AnalysisRequest _callback(CompletionRequest request, var value) {
- expect(value, isNotNull);
- return _nextAnalysisRequest(request);
- }
-
- AnalysisRequest _nextAnalysisRequest(CompletionRequest request) {
- if (descriptors.length == 0) {
- return null;
- }
- return new AnalysisRequest(
- request.source, descriptors.removeAt(0), _callback);
+ return new Future.value();
}
}
@@ -872,7 +825,7 @@
}
CompletionManager createCompletionManager(
- AnalysisContext context, Source source, SearchEngine searchEngine) {
+ AnalysisServer server, AnalysisContext context, Source source) {
return new MockCompletionManager(mockContext, source, searchEngine);
}
}
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index fdb336e..444e6cf 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -42,6 +42,10 @@
handler = new DiagnosticDomainHandler(server);
});
+ tearDown(() {
+ handler.sampler?.stop();
+ });
+
group('DiagnosticDomainHandler', () {
test('getDiagnostics', () async {
String file = '/project/bin/test.dart';
@@ -64,6 +68,7 @@
expect(context['explicitFileCount'], fileCount);
expect(context['implicitFileCount'], 0);
expect(context['workItemQueueLength'], isNotNull);
+ expect(context['workItemQueueLengthAverage'], isNotNull);
});
test('getDiagnostics - (no root)', () async {
diff --git a/pkg/analysis_server/test/edit/assists_test.dart b/pkg/analysis_server/test/edit/assists_test.dart
index b6572c4..538a04e 100644
--- a/pkg/analysis_server/test/edit/assists_test.dart
+++ b/pkg/analysis_server/test/edit/assists_test.dart
@@ -4,8 +4,6 @@
library test.edit.assists;
-import 'dart:async';
-
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/edit/edit_domain.dart';
import 'package:plugin/manager.dart';
@@ -24,15 +22,15 @@
class AssistsTest extends AbstractAnalysisTest {
List<SourceChange> changes;
- void prepareAssists(String search, [int length = 0]) {
+ prepareAssists(String search, [int length = 0]) async {
int offset = findOffset(search);
- prepareAssistsAt(offset, length);
+ await prepareAssistsAt(offset, length);
}
- void prepareAssistsAt(int offset, int length) {
+ prepareAssistsAt(int offset, int length) async {
Request request =
new EditGetAssistsParams(testFile, offset, length).toRequest('0');
- Response response = handleSuccessfulRequest(request);
+ Response response = await waitResponse(request);
var result = new EditGetAssistsResult.fromResponse(response);
changes = result.assists;
}
@@ -46,14 +44,14 @@
handler = new EditDomainHandler(server);
}
- Future test_removeTypeAnnotation() async {
+ test_removeTypeAnnotation() async {
addTestFile('''
main() {
int v = 1;
}
''');
await waitForTasksFinished();
- prepareAssists('v =');
+ await prepareAssists('v =');
_assertHasChange(
'Remove type annotation',
'''
@@ -63,14 +61,14 @@
''');
}
- Future test_splitVariableDeclaration() async {
+ test_splitVariableDeclaration() async {
addTestFile('''
main() {
int v = 1;
}
''');
await waitForTasksFinished();
- prepareAssists('v =');
+ await prepareAssists('v =');
_assertHasChange(
'Split variable declaration',
'''
@@ -81,7 +79,7 @@
''');
}
- Future test_surroundWithIf() async {
+ test_surroundWithIf() async {
addTestFile('''
main() {
print(1);
@@ -91,7 +89,7 @@
await waitForTasksFinished();
int offset = findOffset(' print(1)');
int length = findOffset('}') - offset;
- prepareAssistsAt(offset, length);
+ await prepareAssistsAt(offset, length);
_assertHasChange(
"Surround with 'if'",
'''
diff --git a/pkg/analysis_server/test/edit/fixes_test.dart b/pkg/analysis_server/test/edit/fixes_test.dart
index 531bf43..fb2ee76 100644
--- a/pkg/analysis_server/test/edit/fixes_test.dart
+++ b/pkg/analysis_server/test/edit/fixes_test.dart
@@ -33,14 +33,14 @@
handler = new EditDomainHandler(server);
}
- Future test_fixUndefinedClass() async {
+ test_fixUndefinedClass() async {
addTestFile('''
main() {
Future<String> x = null;
}
''');
await waitForTasksFinished();
- List<AnalysisErrorFixes> errorFixes = _getFixesAt('Future<String>');
+ List<AnalysisErrorFixes> errorFixes = await _getFixesAt('Future<String>');
expect(errorFixes, hasLength(1));
AnalysisError error = errorFixes[0].error;
expect(error.severity, AnalysisErrorSeverity.WARNING);
@@ -51,7 +51,7 @@
expect(fixes[1].message, matches('Create class'));
}
- Future test_hasFixes() async {
+ test_hasFixes() async {
addTestFile('''
foo() {
print(1)
@@ -63,20 +63,20 @@
await waitForTasksFinished();
// print(1)
{
- List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(1)');
+ List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(1)');
expect(errorFixes, hasLength(1));
_isSyntacticErrorWithSingleFix(errorFixes[0]);
}
// print(10)
{
- List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(10)');
+ List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(10)');
expect(errorFixes, hasLength(2));
_isSyntacticErrorWithSingleFix(errorFixes[0]);
_isSyntacticErrorWithSingleFix(errorFixes[1]);
}
}
- Future test_overlayOnlyFile() async {
+ test_overlayOnlyFile() async {
// add an overlay-only file
{
testCode = '''
@@ -92,21 +92,21 @@
}
// ask for fixes
await waitForTasksFinished();
- List<AnalysisErrorFixes> errorFixes = _getFixesAt('print(1)');
+ List<AnalysisErrorFixes> errorFixes = await _getFixesAt('print(1)');
expect(errorFixes, hasLength(1));
_isSyntacticErrorWithSingleFix(errorFixes[0]);
}
- List<AnalysisErrorFixes> _getFixes(int offset) {
+ Future<List<AnalysisErrorFixes>> _getFixes(int offset) async {
Request request = new EditGetFixesParams(testFile, offset).toRequest('0');
- Response response = handleSuccessfulRequest(request);
+ Response response = await waitResponse(request);
var result = new EditGetFixesResult.fromResponse(response);
return result.fixes;
}
- List<AnalysisErrorFixes> _getFixesAt(String search) {
+ Future<List<AnalysisErrorFixes>> _getFixesAt(String search) async {
int offset = findOffset(search);
- return _getFixes(offset);
+ return await _getFixes(offset);
}
void _isSyntacticErrorWithSingleFix(AnalysisErrorFixes fixes) {
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 24933ef..af165f2 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -238,6 +238,41 @@
}
/**
+ * 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.
*
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 6663f98..2a0cd06 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -153,6 +153,30 @@
}));
/**
+ * 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
*/
final Matcher isAnalysisGetLibraryDependenciesParams = isNull;
@@ -1283,6 +1307,7 @@
* "explicitFileCount": int
* "implicitFileCount": int
* "workItemQueueLength": int
+ * "workItemQueueLengthAverage": String
* "cacheEntryExceptions": List<String>
* }
*/
@@ -1292,6 +1317,7 @@
"explicitFileCount": isInt,
"implicitFileCount": isInt,
"workItemQueueLength": isInt,
+ "workItemQueueLengthAverage": isString,
"cacheEntryExceptions": isListOf(isString)
}));
@@ -2075,6 +2101,7 @@
* 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
@@ -2100,6 +2127,7 @@
"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",
diff --git a/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
deleted file mode 100644
index f0698a0..0000000
--- a/pkg/analysis_server/test/services/completion/combinator_contributor_test.dart
+++ /dev/null
@@ -1,141 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.services.completion.dart.combinator;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-
-import '../../utils.dart';
-import 'completion_test_util.dart';
-
-main() {
- initializeTestEnvironment();
- defineReflectiveTests(CombinatorContributorTest);
-}
-
-@reflectiveTest
-class CombinatorContributorTest extends AbstractCompletionTest {
- @override
- void setUpContributor() {
- contributor = new CombinatorContributor();
- }
-
- test_Block_inherited_local() {
- // Block BlockFunctionBody MethodDeclaration ClassDeclaration
- addTestSource('''
- class F { var f1; f2() { } }
- class E extends F { var e1; e2() { } }
- class I { int i1; i2() { } }
- class M { var m1; int m2() { } }
- class A extends E implements I with M {a() {^}}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
- }
-
- test_Combinator_hide() {
- // SimpleIdentifier HideCombinator ImportDirective
- addSource(
- '/testAB.dart',
- '''
- library libAB;
- part '/partAB.dart';
- class A { }
- class B { }''');
- addSource(
- '/partAB.dart',
- '''
- part of libAB;
- var T1;
- PB F1() => new PB();
- class PB { }''');
- addSource(
- '/testCD.dart',
- '''
- class C { }
- class D { }''');
- addTestSource('''
- import "/testAB.dart" hide ^;
- import "/testCD.dart";
- class X {}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestClass('A',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestClass('B',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestClass('PB',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestTopLevelVar('T1', null, DART_RELEVANCE_DEFAULT,
- CompletionSuggestionKind.IDENTIFIER);
- assertSuggestFunction('F1', 'PB',
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertNotSuggested('C');
- assertNotSuggested('D');
- assertNotSuggested('X');
- assertNotSuggested('Object');
- });
- }
-
- test_Combinator_show() {
- // SimpleIdentifier HideCombinator ImportDirective
- addSource(
- '/testAB.dart',
- '''
- library libAB;
- part '/partAB.dart';
- class A { }
- class B { }''');
- addSource(
- '/partAB.dart',
- '''
- part of libAB;
- var T1;
- PB F1() => new PB();
- typedef PB2 F2(int blat);
- class Clz = Object with Object;
- class PB { }''');
- addSource(
- '/testCD.dart',
- '''
- class C { }
- class D { }''');
- addTestSource('''
- import "/testAB.dart" show ^;
- import "/testCD.dart";
- class X {}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestClass('A',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestClass('B',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestClass('PB',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestTopLevelVar('T1', null, DART_RELEVANCE_DEFAULT,
- CompletionSuggestionKind.IDENTIFIER);
- assertSuggestFunction('F1', 'PB',
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestClass('Clz',
- relevance: DART_RELEVANCE_DEFAULT,
- kind: CompletionSuggestionKind.IDENTIFIER);
- assertSuggestFunctionTypeAlias('F2', null, false, DART_RELEVANCE_DEFAULT,
- CompletionSuggestionKind.IDENTIFIER);
- assertNotSuggested('C');
- assertNotSuggested('D');
- assertNotSuggested('X');
- assertNotSuggested('Object');
- });
- }
-}
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 21b3393..3614852 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -7,9 +7,9 @@
import 'dart:async';
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/provisional/completion/completion_core.dart'
show CompletionRequest, CompletionResult;
+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_completion_manager.dart';
import 'package:analysis_server/src/services/index/index.dart';
@@ -22,7 +22,6 @@
import 'package:unittest/unittest.dart';
import '../../abstract_single_unit.dart';
-import '../../operation/operation_queue_test.dart';
import '../../utils.dart';
main() {
@@ -67,7 +66,8 @@
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,
@@ -86,9 +86,8 @@
manager.contributors = [contributor1, contributor2];
int count = 0;
bool done = false;
- AnalysisServer server = new AnalysisServerMock(searchEngine: searchEngine);
CompletionRequest completionRequest =
- new CompletionRequestImpl(server, context, source, 0);
+ new CompletionRequestImpl(context, provider, searchEngine, source, 0);
manager.results(completionRequest).listen((CompletionResult r) {
bool isLast = r is CompletionResultImpl ? r.isLast : true;
switch (++count) {
@@ -113,7 +112,7 @@
// There is only one notification
expect(count, equals(1));
});
- return pumpEventQueue(150).then((_) {
+ return pumpEventQueue(250).then((_) {
expect(done, isTrue);
});
}
@@ -124,9 +123,8 @@
manager.contributors = [contributor1, contributor2];
int count = 0;
bool done = false;
- AnalysisServer server = new AnalysisServerMock(searchEngine: searchEngine);
CompletionRequest completionRequest =
- new CompletionRequestImpl(server, context, source, 0);
+ new CompletionRequestImpl(context, provider, searchEngine, source, 0);
manager.results(completionRequest).listen((CompletionResult r) {
bool isLast = r is CompletionResultImpl ? r.isLast : true;
switch (++count) {
diff --git a/pkg/analysis_server/test/services/completion/completion_manager_test.dart b/pkg/analysis_server/test/services/completion/completion_manager_test.dart
index eab5223..4ee538d 100644
--- a/pkg/analysis_server/test/services/completion/completion_manager_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_manager_test.dart
@@ -24,25 +24,25 @@
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);
}
}
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index a533731..29108ca 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -10,10 +10,9 @@
show Element, ElementKind;
import 'package:analysis_server/plugin/protocol/protocol.dart'
hide Element, ElementKind;
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.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_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -28,7 +27,6 @@
import 'package:unittest/unittest.dart';
import '../../abstract_context.dart';
-import '../../operation/operation_queue_test.dart';
int suggestionComparator(CompletionSuggestion s1, CompletionSuggestion s2) {
String c1 = s1.completion.toLowerCase();
@@ -66,10 +64,8 @@
content.substring(completionOffset + 1);
testSource = addSource(testFile, content);
cache = new DartCompletionCache(context, testSource);
- AnalysisServer server = new AnalysisServerMock(
- searchEngine: searchEngine, resourceProvider: provider);
request = new DartCompletionRequest(
- server, context, testSource, completionOffset, cache);
+ context, provider, searchEngine, testSource, completionOffset, cache);
}
void assertHasNoParameterInfo(CompletionSuggestion suggestion) {
@@ -441,7 +437,7 @@
bool computeFast() {
expect(computeFastResult, isNull);
_completionManager = new DartCompletionManager(context, searchEngine,
- testSource, cache, [contributor], new CommonUsageComputer({}));
+ testSource, cache, [contributor], [], new CommonUsageSorter({}));
var result =
_completionManager.computeFast(request, new CompletionPerformance());
expect(request.replacementOffset, isNotNull);
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
similarity index 63%
rename from pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index 9bb8aa7..273509c 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -5,13 +5,13 @@
library test.services.completion.dart.arglist;
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/arglist_contributor.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
main() {
initializeTestEnvironment();
@@ -19,9 +19,9 @@
}
@reflectiveTest
-class ArgListContributorTest extends AbstractCompletionTest {
+class ArgListContributorTest extends DartCompletionContributorTest {
void assertNoOtherSuggestions(Iterable<CompletionSuggestion> expected) {
- for (CompletionSuggestion suggestion in request.suggestions) {
+ for (CompletionSuggestion suggestion in suggestions) {
if (!expected.contains(suggestion)) {
failedCompletion('did not expect completion: '
'${suggestion.completion}\n $suggestion');
@@ -34,7 +34,7 @@
CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
CompletionSuggestion cs = getSuggest(csKind: csKind);
if (cs == null) {
- failedCompletion('expected completion $csKind', request.suggestions);
+ failedCompletion('expected completion $csKind', suggestions);
}
assertSuggestArgumentList_params(
paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
@@ -86,50 +86,51 @@
}
@override
- void setUpContributor() {
- contributor = new ArgListContributor();
+ DartCompletionContributor createContributor() {
+ return new ArgListContributor();
}
- test_Annotation_local_constructor_named_param() {
- //
+ test_Annotation_local_constructor_named_param() async {
addTestSource('''
class A { A({int one, String two: 'defaultValue'}) { } }
@A(^) main() { }''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['one', 'two']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one', 'two']);
}
- test_ArgumentList_getter() {
+ test_Annotation_imported_constructor_named_param() async {
+ addSource(
+ '/libA.dart',
+ '''
+library libA; class A { A({int one, String two: 'defaultValue'}) { } }''');
+ addTestSource('import "/libA.dart"; @A(^) main() { }');
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one', 'two']);
+ }
+
+ test_ArgumentList_getter() async {
addTestSource('class A {int get foo => 7; main() {foo(^)}');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_constructor_named_param() {
+ test_ArgumentList_imported_constructor_named_param() async {
//
addSource('/libA.dart', 'library libA; class A{A({int one}){}}');
addTestSource('import "/libA.dart"; main() { new A(^);}');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['one']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one']);
}
- test_ArgumentList_imported_constructor_named_param2() {
+ test_ArgumentList_imported_constructor_named_param2() async {
//
addSource('/libA.dart', 'library libA; class A{A.foo({int one}){}}');
addTestSource('import "/libA.dart"; main() { new A.foo(^);}');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['one']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one']);
}
- test_ArgumentList_imported_function_0() {
+ test_ArgumentList_imported_function_0() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -143,13 +144,11 @@
class B { }
String bar() => true;
void main() {expect(a^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_function_1() {
+ test_ArgumentList_imported_function_1() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -163,13 +162,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg'], ['String']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg'], ['String']);
}
- test_ArgumentList_imported_function_2() {
+ test_ArgumentList_imported_function_2() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -183,13 +180,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
}
- test_ArgumentList_imported_function_3() {
+ test_ArgumentList_imported_function_3() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -203,13 +198,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg1', 'arg2'], ['String', 'int']);
}
- test_ArgumentList_imported_function_3a() {
+ test_ArgumentList_imported_function_3a() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -223,13 +216,11 @@
class B { }
String bar() => true;
void main() {expect('hello', ^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_function_3b() {
+ test_ArgumentList_imported_function_3b() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -243,13 +234,11 @@
class B { }
String bar() => true;
void main() {expect('hello', ^x)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_function_3c() {
+ test_ArgumentList_imported_function_3c() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -263,13 +252,11 @@
class B { }
String bar() => true;
void main() {expect('hello', x^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_function_3d() {
+ test_ArgumentList_imported_function_3d() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -283,71 +270,57 @@
class B { }
String bar() => true;
void main() {expect('hello', x ^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_imported_function_named_param() {
+ test_ArgumentList_imported_function_named_param() async {
//
addTestSource('main() { int.parse("16", ^);}');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['radix', 'onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
}
- test_ArgumentList_imported_function_named_param1() {
+ test_ArgumentList_imported_function_named_param1() async {
//
addTestSource('main() { int.parse("16", r^);}');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['radix', 'onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
}
- test_ArgumentList_imported_function_named_param2() {
+ test_ArgumentList_imported_function_named_param2() async {
//
addTestSource('main() { int.parse("16", radix: 7, ^);}');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['onError']);
}
- test_ArgumentList_imported_function_named_param2a() {
+ test_ArgumentList_imported_function_named_param2a() async {
//
addTestSource('main() { int.parse("16", radix: ^);}');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_constructor_named_param() {
+ test_ArgumentList_local_constructor_named_param() async {
//
addTestSource('''
class A { A({int one, String two: 'defaultValue'}) { } }
main() { new A(^);}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['one', 'two']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one', 'two']);
}
- test_ArgumentList_local_constructor_named_param2() {
+ test_ArgumentList_local_constructor_named_param2() async {
//
addTestSource('''
class A { A.foo({int one, String two: 'defaultValue'}) { } }
main() { new A.foo(^);}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['one', 'two']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['one', 'two']);
}
- test_ArgumentList_local_function_1() {
+ test_ArgumentList_local_function_1() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -355,13 +328,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg'], ['dynamic']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg'], ['dynamic']);
}
- test_ArgumentList_local_function_2() {
+ test_ArgumentList_local_function_2() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -369,13 +340,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
}
- test_ArgumentList_local_function_3() {
+ test_ArgumentList_local_function_3() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -383,13 +352,11 @@
class B { }
String bar() => true;
void main() {expect(^)}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg1', 'arg2'], ['dynamic', 'int']);
}
- test_ArgumentList_local_function_3a() {
+ test_ArgumentList_local_function_3a() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -397,13 +364,11 @@
class B { }
String bar() => true;
void main() {expect('hello', ^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_function_3b() {
+ test_ArgumentList_local_function_3b() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -411,13 +376,11 @@
class B { }
String bar() => true;
void main() {expect('hello', ^x)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_function_3c() {
+ test_ArgumentList_local_function_3c() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -425,13 +388,11 @@
class B { }
String bar() => true;
void main() {expect('hello', x^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_function_3d() {
+ test_ArgumentList_local_function_3d() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addTestSource('''
import '/libA.dart'
@@ -439,57 +400,47 @@
class B { }
String bar() => true;
void main() {expect('hello', x ^)}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_function_named_param() {
+ test_ArgumentList_local_function_named_param() async {
//
addTestSource('''
f(v,{int radix, int onError(String s)}){}
main() { f("16", ^);}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['radix', 'onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
}
- test_ArgumentList_local_function_named_param1() {
+ test_ArgumentList_local_function_named_param1() async {
//
addTestSource('''
f(v,{int radix, int onError(String s)}){}
main() { f("16", r^);}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['radix', 'onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
}
- test_ArgumentList_local_function_named_param2() {
+ test_ArgumentList_local_function_named_param2() async {
//
addTestSource('''
f(v,{int radix, int onError(String s)}){}
main() { f("16", radix: 7, ^);}''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArguments(namedArguments: ['onError']);
- });
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['onError']);
}
- test_ArgumentList_local_function_named_param2a() {
+ test_ArgumentList_local_function_named_param2a() async {
//
addTestSource('''
f(v,{int radix, int onError(String s)}){}
main() { f("16", radix: ^);}''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_method_0() {
+ test_ArgumentList_local_method_0() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -503,13 +454,11 @@
expect() { }
void foo() {expect(^)}}
String bar() => true;''');
- computeFast();
- return computeFull((bool result) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_ArgumentList_local_method_2() {
+ test_ArgumentList_local_method_2() async {
// ArgumentList MethodInvocation ExpressionStatement Block
addSource(
'/libA.dart',
@@ -523,9 +472,7 @@
expect(arg, int blat) { }
void foo() {expect(^)}}
String bar() => true;''');
- computeFast();
- return computeFull((bool result) {
- assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
- });
+ await computeSuggestions();
+ assertSuggestArgumentList(['arg', 'blat'], ['dynamic', 'int']);
}
}
diff --git a/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
new file mode 100644
index 0000000..be250e7
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/combinator_contributor_test.dart
@@ -0,0 +1,151 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.combinator;
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/combinator_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(CombinatorContributorTest);
+}
+
+@reflectiveTest
+class CombinatorContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new CombinatorContributor();
+ }
+
+ test_Block_inherited_local() async {
+ // Block BlockFunctionBody MethodDeclaration ClassDeclaration
+ addTestSource('''
+ class F { var f1; f2() { } }
+ class E extends F { var e1; e2() { } }
+ class I { int i1; i2() { } }
+ class M { var m1; int m2() { } }
+ class A extends E implements I with M {a() {^}}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_Combinator_hide() async {
+ // SimpleIdentifier HideCombinator ImportDirective
+ Source importedLibSource = addSource(
+ '/testAB.dart',
+ '''
+ library libAB;
+ part '/partAB.dart';
+ class A { }
+ class B { }''');
+ addSource(
+ '/partAB.dart',
+ '''
+ part of libAB;
+ var T1;
+ PB F1() => new PB();
+ class PB { }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ class C { }
+ class D { }''');
+ addTestSource('''
+ import "/testAB.dart" hide ^;
+ import "/testCD.dart";
+ class X {}''');
+
+ // Assume that imported libraries have been resolved
+ context.resolveCompilationUnit2(importedLibSource, importedLibSource);
+
+ await computeSuggestions();
+ assertSuggestClass('A',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestClass('B',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestClass('PB',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestTopLevelVar('T1', null,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestFunction('F1', 'PB',
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertNotSuggested('C');
+ assertNotSuggested('D');
+ assertNotSuggested('X');
+ assertNotSuggested('Object');
+ }
+
+ test_Combinator_show() async {
+ // SimpleIdentifier HideCombinator ImportDirective
+ Source importedLibSource = addSource(
+ '/testAB.dart',
+ '''
+ library libAB;
+ part '/partAB.dart';
+ class A { }
+ class B { }''');
+ addSource(
+ '/partAB.dart',
+ '''
+ part of libAB;
+ var T1;
+ PB F1() => new PB();
+ typedef PB2 F2(int blat);
+ class Clz = Object with Object;
+ class PB { }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ class C { }
+ class D { }''');
+ addTestSource('''
+ import "/testAB.dart" show ^;
+ import "/testCD.dart";
+ class X {}''');
+
+ // Assume that imported libraries have been resolved
+ context.resolveCompilationUnit2(importedLibSource, importedLibSource);
+
+ await computeSuggestions();
+ assertSuggestClass('A',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestClass('B',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestClass('PB',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestTopLevelVar('T1', null,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestFunction('F1', 'PB',
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestClass('Clz',
+ relevance: DART_RELEVANCE_DEFAULT,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestFunctionTypeAlias('F2', null, false, DART_RELEVANCE_DEFAULT,
+ CompletionSuggestionKind.IDENTIFIER);
+ assertNotSuggested('C');
+ assertNotSuggested('D');
+ assertNotSuggested('X');
+ assertNotSuggested('Object');
+ }
+
+ test_Combinator_show_PI() async {
+ addTestSource('import "dart:math" show ^;');
+ await computeSuggestions();
+ assertSuggestTopLevelVar('PI', 'double',
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/common_usage_computer_test.dart b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
similarity index 94%
rename from pkg/analysis_server/test/services/completion/common_usage_computer_test.dart
rename to pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
index 8ed33f1..66b236d 100644
--- a/pkg/analysis_server/test/services/completion/common_usage_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/common_usage_sorter_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library test.services.completion.computer.dart.relevance;
+library test.services.completion.dart.sorter.common;
import 'dart:async';
@@ -11,7 +11,7 @@
show ContextSourcePair;
import 'package:analysis_server/src/constants.dart';
import 'package:analysis_server/src/domain_completion.dart';
-import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
+import 'package:analysis_server/src/services/completion/dart/common_usage_sorter.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/index/index.dart';
@@ -21,17 +21,17 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
-import '../../analysis_abstract.dart';
-import '../../mocks.dart';
-import '../../utils.dart';
+import '../../../analysis_abstract.dart';
+import '../../../mocks.dart';
+import '../../../utils.dart';
main() {
initializeTestEnvironment();
- defineReflectiveTests(CommonUsageComputerTest);
+ defineReflectiveTests(CommonUsageSorterTest);
}
@reflectiveTest
-class CommonUsageComputerTest extends AbstractAnalysisTest {
+class CommonUsageSorterTest extends AbstractAnalysisTest {
String completionId;
int completionOffset;
int replacementOffset;
@@ -107,7 +107,8 @@
source,
new DartCompletionCache(context, source),
null,
- new CommonUsageComputer(selectorRelevance));
+ server.serverPlugin.completionContributors,
+ new CommonUsageSorter(selectorRelevance));
Response response =
domainHandler.processRequest(request, completionManager);
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
new file mode 100644
index 0000000..c08a073
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -0,0 +1,340 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart.util;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart' as protocol
+ show Element, ElementKind;
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/completion_core.dart';
+import 'package:analysis_server/src/services/completion/dart/completion_manager.dart'
+ show DartCompletionRequestImpl;
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
+ show DART_RELEVANCE_DEFAULT, DART_RELEVANCE_LOW, ReplacementRange;
+import 'package:analysis_server/src/services/index/index.dart';
+import 'package:analysis_server/src/services/index/local_memory_index.dart';
+import 'package:analysis_server/src/services/search/search_engine_internal.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../abstract_context.dart';
+
+int suggestionComparator(CompletionSuggestion s1, CompletionSuggestion s2) {
+ String c1 = s1.completion.toLowerCase();
+ String c2 = s2.completion.toLowerCase();
+ return c1.compareTo(c2);
+}
+
+abstract class DartCompletionContributorTest extends AbstractContextTest {
+ Index index;
+ SearchEngineImpl searchEngine;
+ String testFile = '/completionTest.dart';
+ Source testSource;
+ int completionOffset;
+ int replacementOffset;
+ int replacementLength;
+ DartCompletionContributor contributor;
+ DartCompletionRequest request;
+ List<CompletionSuggestion> suggestions;
+
+ void addTestSource(String content) {
+ expect(completionOffset, isNull, reason: 'Call addTestUnit exactly once');
+ completionOffset = content.indexOf('^');
+ expect(completionOffset, isNot(equals(-1)), reason: 'missing ^');
+ int nextOffset = content.indexOf('^', completionOffset + 1);
+ expect(nextOffset, equals(-1), reason: 'too many ^');
+ content = content.substring(0, completionOffset) +
+ content.substring(completionOffset + 1);
+ testSource = addSource(testFile, content);
+ }
+
+ void assertHasNoParameterInfo(CompletionSuggestion suggestion) {
+ expect(suggestion.parameterNames, isNull);
+ expect(suggestion.parameterTypes, isNull);
+ expect(suggestion.requiredParameterCount, isNull);
+ expect(suggestion.hasNamedParameters, isNull);
+ }
+
+ void assertHasParameterInfo(CompletionSuggestion suggestion) {
+ expect(suggestion.parameterNames, isNotNull);
+ expect(suggestion.parameterTypes, isNotNull);
+ expect(suggestion.parameterNames.length, suggestion.parameterTypes.length);
+ expect(suggestion.requiredParameterCount,
+ lessThanOrEqualTo(suggestion.parameterNames.length));
+ expect(suggestion.hasNamedParameters, isNotNull);
+ }
+
+ void assertNoSuggestions({CompletionSuggestionKind kind: null}) {
+ if (kind == null) {
+ if (suggestions.length > 0) {
+ failedCompletion('Expected no suggestions', suggestions);
+ }
+ return;
+ }
+ CompletionSuggestion suggestion = suggestions.firstWhere(
+ (CompletionSuggestion cs) => cs.kind == kind,
+ orElse: () => null);
+ if (suggestion != null) {
+ failedCompletion('did not expect completion: $completion\n $suggestion');
+ }
+ }
+
+ void assertNotSuggested(String completion) {
+ CompletionSuggestion suggestion = suggestions.firstWhere(
+ (CompletionSuggestion cs) => cs.completion == completion,
+ orElse: () => null);
+ if (suggestion != null) {
+ failedCompletion('did not expect completion: $completion\n $suggestion');
+ }
+ }
+
+ CompletionSuggestion assertSuggest(String completion,
+ {CompletionSuggestionKind csKind: CompletionSuggestionKind.INVOCATION,
+ int relevance: DART_RELEVANCE_DEFAULT,
+ String importUri,
+ protocol.ElementKind elemKind: null,
+ bool isDeprecated: false,
+ bool isPotential: false,
+ String elemFile,
+ int elemOffset}) {
+ CompletionSuggestion cs =
+ getSuggest(completion: completion, csKind: csKind, elemKind: elemKind);
+ if (cs == null) {
+ failedCompletion('expected $completion $csKind $elemKind', suggestions);
+ }
+ expect(cs.kind, equals(csKind));
+ if (isDeprecated) {
+ expect(cs.relevance, equals(DART_RELEVANCE_LOW));
+ } else {
+ expect(cs.relevance, equals(relevance));
+ }
+ expect(cs.importUri, importUri);
+ expect(cs.selectionOffset, equals(completion.length));
+ expect(cs.selectionLength, equals(0));
+ expect(cs.isDeprecated, equals(isDeprecated));
+ expect(cs.isPotential, equals(isPotential));
+ if (cs.element != null) {
+ expect(cs.element.location, isNotNull);
+ expect(cs.element.location.file, isNotNull);
+ expect(cs.element.location.offset, isNotNull);
+ expect(cs.element.location.length, isNotNull);
+ expect(cs.element.location.startColumn, isNotNull);
+ expect(cs.element.location.startLine, isNotNull);
+ }
+ if (elemFile != null) {
+ expect(cs.element.location.file, elemFile);
+ }
+ if (elemOffset != null) {
+ expect(cs.element.location.offset, elemOffset);
+ }
+ return cs;
+ }
+
+ CompletionSuggestion assertSuggestClass(String name,
+ {int relevance: DART_RELEVANCE_DEFAULT,
+ String importUri,
+ CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+ bool isDeprecated: false,
+ String elemFile,
+ int elemOffset}) {
+ CompletionSuggestion cs = assertSuggest(name,
+ csKind: kind,
+ relevance: relevance,
+ importUri: importUri,
+ isDeprecated: isDeprecated,
+ elemFile: elemFile,
+ elemOffset: elemOffset);
+ protocol.Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(protocol.ElementKind.CLASS));
+ expect(element.name, equals(name));
+ expect(element.parameters, isNull);
+ expect(element.returnType, isNull);
+ assertHasNoParameterInfo(cs);
+ return cs;
+ }
+
+ CompletionSuggestion assertSuggestFunction(String name, String returnType,
+ {CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+ bool deprecated: false,
+ int relevance: DART_RELEVANCE_DEFAULT,
+ String importUri}) {
+ CompletionSuggestion cs = assertSuggest(name,
+ csKind: kind,
+ relevance: relevance,
+ importUri: importUri,
+ isDeprecated: deprecated);
+ expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+ protocol.Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(protocol.ElementKind.FUNCTION));
+ expect(element.name, equals(name));
+ expect(element.isDeprecated, equals(deprecated));
+ String param = element.parameters;
+ expect(param, isNotNull);
+ expect(param[0], equals('('));
+ expect(param[param.length - 1], equals(')'));
+ expect(element.returnType,
+ equals(returnType != null ? returnType : 'dynamic'));
+ assertHasParameterInfo(cs);
+ return cs;
+ }
+
+ CompletionSuggestion assertSuggestFunctionTypeAlias(
+ String name, String returnType, bool isDeprecated,
+ [int relevance = DART_RELEVANCE_DEFAULT,
+ CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION,
+ String importUri]) {
+ CompletionSuggestion cs = assertSuggest(name,
+ csKind: kind,
+ relevance: relevance,
+ importUri: importUri,
+ isDeprecated: isDeprecated);
+ expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+ protocol.Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(protocol.ElementKind.FUNCTION_TYPE_ALIAS));
+ expect(element.name, equals(name));
+ expect(element.isDeprecated, equals(isDeprecated));
+ // TODO (danrubel) Determine why params are null
+ // String param = element.parameters;
+ // expect(param, isNotNull);
+ // expect(param[0], equals('('));
+ // expect(param[param.length - 1], equals(')'));
+ expect(element.returnType,
+ equals(returnType != null ? returnType : 'dynamic'));
+ // TODO (danrubel) Determine why param info is missing
+ // assertHasParameterInfo(cs);
+ return cs;
+ }
+
+ CompletionSuggestion assertSuggestTopLevelVar(String name, String returnType,
+ {int relevance: DART_RELEVANCE_DEFAULT,
+ CompletionSuggestionKind kind: CompletionSuggestionKind.INVOCATION,
+ String importUri}) {
+ CompletionSuggestion cs = assertSuggest(name,
+ csKind: kind, relevance: relevance, importUri: importUri);
+ expect(cs.returnType, returnType != null ? returnType : 'dynamic');
+ protocol.Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(protocol.ElementKind.TOP_LEVEL_VARIABLE));
+ expect(element.name, equals(name));
+ expect(element.parameters, isNull);
+ expect(element.returnType, returnType != null ? returnType : 'dynamic');
+ assertHasNoParameterInfo(cs);
+ return cs;
+ }
+
+ /**
+ * Return a [Future] that completes with the containing library information
+ * after it is accessible via [context.getLibrariesContaining].
+ */
+ Future computeLibrariesContaining([int times = 200]) {
+ List<Source> libraries = context.getLibrariesContaining(testSource);
+ if (libraries.isNotEmpty) {
+ return new Future.value(libraries);
+ }
+ context.performAnalysisTask();
+ // We use a delayed future to allow microtask events to finish. The
+ // Future.value or Future() constructors use scheduleMicrotask themselves and
+ // would therefore not wait for microtask callbacks that are scheduled after
+ // invoking this method.
+ return new Future.delayed(
+ Duration.ZERO, () => computeLibrariesContaining(times - 1));
+ }
+
+ Future computeSuggestions([int times = 200]) async {
+ CompletionRequestImpl baseRequest = new CompletionRequestImpl(
+ context, provider, searchEngine, testSource, completionOffset);
+ request = new DartCompletionRequestImpl.forRequest(baseRequest);
+ var range = new ReplacementRange.compute(request.offset, request.target);
+ replacementOffset = range.offset;
+ replacementLength = range.length;
+ Completer<List<CompletionSuggestion>> completer =
+ new Completer<List<CompletionSuggestion>>();
+
+ // Request completions
+ contributor
+ .computeSuggestions(request)
+ .then((List<CompletionSuggestion> computedSuggestions) {
+ completer.complete(computedSuggestions);
+ });
+
+ // Perform analysis until the suggestions have been computed
+ // or the max analysis cycles ([times]) has been reached
+ suggestions = await performAnalysis(times, completer);
+ expect(suggestions, isNotNull, reason: 'expected suggestions');
+ }
+
+ DartCompletionContributor createContributor();
+
+ void failedCompletion(String message,
+ [Iterable<CompletionSuggestion> completions]) {
+ StringBuffer sb = new StringBuffer(message);
+ if (completions != null) {
+ sb.write('\n found');
+ completions.toList()
+ ..sort(suggestionComparator)
+ ..forEach((CompletionSuggestion suggestion) {
+ sb.write('\n ${suggestion.completion} -> $suggestion');
+ });
+ }
+ fail(sb.toString());
+ }
+
+ CompletionSuggestion getSuggest(
+ {String completion: null,
+ CompletionSuggestionKind csKind: null,
+ protocol.ElementKind elemKind: null}) {
+ CompletionSuggestion cs;
+ if (suggestions != null) {
+ suggestions.forEach((CompletionSuggestion s) {
+ if (completion != null && completion != s.completion) {
+ return;
+ }
+ if (csKind != null && csKind != s.kind) {
+ return;
+ }
+ if (elemKind != null) {
+ protocol.Element element = s.element;
+ if (element == null || elemKind != element.kind) {
+ return;
+ }
+ }
+ if (cs == null) {
+ cs = s;
+ } else {
+ failedCompletion('expected exactly one $cs',
+ suggestions.where((s) => s.completion == completion));
+ }
+ });
+ }
+ return cs;
+ }
+
+ Future performAnalysis(int times, Completer completer) {
+ if (completer.isCompleted) return completer.future;
+ if (times == 0 || context == null) return new Future.value();
+ context.performAnalysisTask();
+ // We use a delayed future to allow microtask events to finish. The
+ // Future.value or Future() constructors use scheduleMicrotask themselves and
+ // would therefore not wait for microtask callbacks that are scheduled after
+ // invoking this method.
+ return new Future.delayed(
+ Duration.ZERO, () => performAnalysis(times - 1, completer));
+ }
+
+ @override
+ void setUp() {
+ super.setUp();
+ index = createLocalMemoryIndex();
+ searchEngine = new SearchEngineImpl(index);
+ contributor = createContributor();
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart
new file mode 100644
index 0000000..4ef42d3
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/inherited_contributor_test.dart
@@ -0,0 +1,121 @@
+// 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.completion.dart.inherited_computer_test;
+
+import 'package:analysis_server/plugin/protocol/protocol.dart'
+ hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/inherited_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
+ hide DartCompletionContributor;
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import 'completion_contributor_util.dart';
+
+main() {
+ // Revisit this contributor and these tests
+ // once DartChangeBuilder API has solidified.
+ // initializeTestEnvironment();
+ // defineReflectiveTests(InheritedContributorTest);
+}
+
+@reflectiveTest
+class InheritedContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new InheritedContributor();
+ }
+
+ test_fromMultipleSuperclasses() async {
+ addTestSource(r'''
+class A {
+ A suggested1(int x) => null;
+ B suggested2(String y) => null;
+}
+class B extends A {
+ B suggested2(String y) => null;
+ C suggested3([String z]) => null;
+}
+class C extends B {
+ sugg^
+}
+''');
+ await computeSuggestions();
+ _assertOverride('''@override
+ A suggested1(int x) {
+ // TODO: implement suggested1
+ return null;
+ }''');
+ _assertOverride(
+ '''@override\n A suggested1(int x) {\n // TODO: implement suggested1\n return null;\n }''');
+ _assertOverride(
+ '''@override\n B suggested2(String y) {\n // TODO: implement suggested2\n return null;\n }''');
+ _assertOverride(
+ '''@override\n C suggested3([String z]) {\n // TODO: implement suggested3\n return null;\n }''');
+ }
+
+ test_fromPart() async {
+ addSource(
+ '/myLib.dart',
+ '''
+library myLib;
+part '$testFile'
+part '/otherPart.dart'
+class A {
+ A suggested1(int x) => null;
+ B suggested2(String y) => null;
+}
+''');
+ addSource(
+ '/otherPart.dart',
+ '''
+part of myLib;
+class B extends A {
+ B suggested2(String y) => null;
+ C suggested3([String z]) => null;
+}
+''');
+ addTestSource(r'''
+part of myLib;
+class C extends B {
+ sugg^
+}
+''');
+ // assume information for context.getLibrariesContaining has been cached
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ _assertOverride('''@override
+ A suggested1(int x) {
+ // TODO: implement suggested1
+ return null;
+ }''');
+ _assertOverride(
+ '''@override\n A suggested1(int x) {\n // TODO: implement suggested1\n return null;\n }''');
+ _assertOverride(
+ '''@override\n B suggested2(String y) {\n // TODO: implement suggested2\n return null;\n }''');
+ _assertOverride(
+ '''@override\n C suggested3([String z]) {\n // TODO: implement suggested3\n return null;\n }''');
+ }
+
+ CompletionSuggestion _assertOverride(String completion) {
+ CompletionSuggestion cs = getSuggest(
+ completion: completion,
+ csKind: CompletionSuggestionKind.IDENTIFIER,
+ elemKind: null);
+ if (cs == null) {
+ failedCompletion('expected $completion', suggestions);
+ }
+ expect(cs.kind, equals(CompletionSuggestionKind.IDENTIFIER));
+ expect(cs.relevance, equals(DART_RELEVANCE_HIGH));
+ expect(cs.importUri, null);
+// expect(cs.selectionOffset, equals(completion.length));
+// expect(cs.selectionLength, equals(0));
+ expect(cs.isDeprecated, isFalse);
+ expect(cs.isPotential, isFalse);
+ expect(cs.element, isNotNull);
+ return cs;
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
similarity index 69%
rename from pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index 4a2085f..8933b0a 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -5,14 +5,14 @@
library test.services.completion.dart.keyword;
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/keyword_contributor.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
main() {
initializeTestEnvironment();
@@ -20,7 +20,7 @@
}
@reflectiveTest
-class KeywordContributorTest extends AbstractCompletionTest {
+class KeywordContributorTest extends DartCompletionContributorTest {
static const List<Keyword> CLASS_BODY_KEYWORDS = const [
Keyword.CONST,
Keyword.DYNAMIC,
@@ -221,7 +221,7 @@
Set<String> actualCompletions = new Set<String>();
expectedCompletions.addAll(expectedKeywords.map((k) => k.syntax));
expectedCompletions.addAll(pseudoKeywords);
- for (CompletionSuggestion s in request.suggestions) {
+ for (CompletionSuggestion s in suggestions) {
if (s.kind == CompletionSuggestionKind.KEYWORD) {
Keyword k = Keyword.keywords[s.completion];
if (k == null && !expectedCompletions.contains(s.completion)) {
@@ -241,7 +241,7 @@
_appendCompletions(msg, actualCompletions, expectedCompletions);
fail(msg.toString());
}
- for (CompletionSuggestion s in request.suggestions) {
+ for (CompletionSuggestion s in suggestions) {
if (s.kind == CompletionSuggestionKind.KEYWORD) {
if (s.completion.startsWith(Keyword.IMPORT.syntax)) {
int importRelevance = relevance;
@@ -269,420 +269,420 @@
}
}
- fail_import_partial() {
+ fail_import_partial() async {
addTestSource('imp^ import "package:foo/foo.dart"; import "bar.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO(danrubel) should not suggest declaration keywords
assertNotSuggested('class');
}
- fail_import_partial4() {
+ fail_import_partial4() async {
addTestSource('^ imp import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO(danrubel) should not suggest declaration keywords
assertNotSuggested('class');
}
- fail_import_partial5() {
+ fail_import_partial5() async {
addTestSource('library libA; imp^ import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO(danrubel) should not suggest declaration keywords
assertNotSuggested('class');
}
- fail_import_partial6() {
+ fail_import_partial6() async {
addTestSource(
'library bar; import "zoo.dart"; imp^ import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO(danrubel) should not suggest declaration keywords
assertNotSuggested('class');
}
@override
- void setUpContributor() {
- contributor = new KeywordContributor();
+ DartCompletionContributor createContributor() {
+ return new KeywordContributor();
}
- test_after_class() {
+ test_after_class() async {
addTestSource('class A {} ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS, relevance: DART_RELEVANCE_HIGH);
}
- test_after_class2() {
+ test_after_class2() async {
addTestSource('class A {} c^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS, relevance: DART_RELEVANCE_HIGH);
}
- test_after_import() {
+ test_after_import() async {
addTestSource('import "foo"; ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_after_import2() {
+ test_after_import2() async {
addTestSource('import "foo"; c^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_anonymous_function_async() {
+ test_anonymous_function_async() async {
addTestSource('main() {foo(() ^ {}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_anonymous_function_async2() {
+ test_anonymous_function_async2() async {
addTestSource('main() {foo(() a^ {}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['async']);
}
- test_anonymous_function_async3() {
+ test_anonymous_function_async3() async {
addTestSource('main() {foo(() async ^ {}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_argument() {
+ test_argument() async {
addTestSource('main() {foo(^);}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_argument2() {
+ test_argument2() async {
addTestSource('main() {foo(n^);}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_argument_literal() {
+ test_argument_literal() async {
addTestSource('main() {foo("^");}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_argument_named() {
+ test_argument_named() async {
addTestSource('main() {foo(bar: ^);}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_argument_named2() {
+ test_argument_named2() async {
addTestSource('main() {foo(bar: n^);}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_argument_named_literal() {
+ test_argument_named_literal() async {
addTestSource('main() {foo(bar: "^");}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_assignment_field() {
+ test_assignment_field() async {
addTestSource('class A {var foo = ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_assignment_field2() {
+ test_assignment_field2() async {
addTestSource('class A {var foo = n^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_assignment_local() {
+ test_assignment_local() async {
addTestSource('main() {var foo = ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_assignment_local2() {
+ test_assignment_local2() async {
addTestSource('main() {var foo = n^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_assignment_local2_async() {
+ test_assignment_local2_async() async {
addTestSource('main() async {var foo = n^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE,
pseudoKeywords: ['await']);
}
- test_assignment_local_async() {
+ test_assignment_local_async() async {
addTestSource('main() async {var foo = ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE,
pseudoKeywords: ['await']);
}
- test_before_import() {
+ test_before_import() async {
addTestSource('^ import foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(
[Keyword.EXPORT, Keyword.IMPORT, Keyword.LIBRARY, Keyword.PART],
relevance: DART_RELEVANCE_HIGH);
}
- test_catch() {
+ test_catch() async {
addTestSource('main() {try {} catch (e) {^}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
var keywords = <Keyword>[];
keywords.addAll(STMT_START_OUTSIDE_CLASS);
keywords.add(Keyword.RETHROW);
assertSuggestKeywords(keywords, relevance: DART_RELEVANCE_KEYWORD);
}
- test_class() {
+ test_class() async {
addTestSource('class A e^ { }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_body() {
+ test_class_body() async {
addTestSource('class A {^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS);
}
- test_class_body_beginning() {
+ test_class_body_beginning() async {
addTestSource('class A {^ var foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS);
}
- test_class_body_between() {
+ test_class_body_between() async {
addTestSource('class A {var bar; ^ var foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS);
}
- test_class_body_end() {
+ test_class_body_end() async {
addTestSource('class A {var foo; ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS);
}
- test_class_extends() {
+ test_class_extends() async {
addTestSource('class A extends foo ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_extends2() {
+ test_class_extends2() async {
addTestSource('class A extends foo i^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_extends3() {
+ test_class_extends3() async {
addTestSource('class A extends foo i^ { }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS, Keyword.WITH],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_extends_name() {
+ test_class_extends_name() async {
addTestSource('class A extends ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_class_implements() {
+ test_class_implements() async {
addTestSource('class A ^ implements foo');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.EXTENDS], relevance: DART_RELEVANCE_HIGH);
}
- test_class_implements2() {
+ test_class_implements2() async {
addTestSource('class A e^ implements foo');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO (danrubel) refinement: don't suggest implements
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_implements3() {
+ test_class_implements3() async {
addTestSource('class A e^ implements foo { }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
// TODO (danrubel) refinement: don't suggest implements
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_implements_name() {
+ test_class_implements_name() async {
addTestSource('class A implements ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_class_name() {
+ test_class_name() async {
addTestSource('class ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_class_noBody() {
+ test_class_noBody() async {
addTestSource('class A ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_noBody2() {
+ test_class_noBody2() async {
addTestSource('class A e^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_noBody3() {
+ test_class_noBody3() async {
addTestSource('class A e^ String foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.EXTENDS, Keyword.IMPLEMENTS],
relevance: DART_RELEVANCE_HIGH);
}
- test_class_with() {
+ test_class_with() async {
addTestSource('class A extends foo with bar ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
}
- test_class_with2() {
+ test_class_with2() async {
addTestSource('class A extends foo with bar i^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
}
- test_class_with3() {
+ test_class_with3() async {
addTestSource('class A extends foo with bar i^ { }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IMPLEMENTS], relevance: DART_RELEVANCE_HIGH);
}
- test_class_with_name() {
+ test_class_with_name() async {
addTestSource('class A extends foo with ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_constructor_param() {
+ test_constructor_param() async {
addTestSource('class A { A(^) {});}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.THIS]);
}
- test_constructor_param2() {
+ test_constructor_param2() async {
addTestSource('class A { A(t^) {});}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.THIS]);
}
- test_do_break_continue() {
+ test_do_break_continue() async {
addTestSource('main() {do {^} while (true);}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
- test_do_break_continue2() {
+ test_do_break_continue2() async {
addTestSource('class A {foo() {do {^} while (true);}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
- test_empty() {
+ test_empty() async {
addTestSource('^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_for_break_continue() {
+ test_for_break_continue() async {
addTestSource('main() {for (int x in myList) {^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
- test_for_break_continue2() {
+ test_for_break_continue2() async {
addTestSource('class A {foo() {for (int x in myList) {^}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
- test_for_expression_in() {
+ test_for_expression_in() async {
addTestSource('main() {for (int x i^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IN], relevance: DART_RELEVANCE_HIGH);
}
- test_for_expression_in2() {
+ test_for_expression_in2() async {
addTestSource('main() {for (int x in^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IN], relevance: DART_RELEVANCE_HIGH);
}
- test_for_expression_init() {
+ test_for_expression_init() async {
addTestSource('main() {for (int x = i^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_for_expression_init2() {
+ test_for_expression_init2() async {
addTestSource('main() {for (int x = in^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_function_async() {
+ test_function_async() async {
addTestSource('main()^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_function_async2() {
+ test_function_async2() async {
addTestSource('main()^{}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_function_async3() {
+ test_function_async3() async {
addTestSource('main()a^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_function_async4() {
+ test_function_async4() async {
addTestSource('main()a^{}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_function_async5() {
+ test_function_async5() async {
addTestSource('main()a^ Foo foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_function_body_inClass_constructorInitializer() {
+ test_function_body_inClass_constructorInitializer() async {
addTestSource(r'''
foo(p) {}
class A {
@@ -690,11 +690,11 @@
A() : f = foo(() {^});
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_function_body_inClass_constructorInitializer_async() {
+ test_function_body_inClass_constructorInitializer_async() async {
addTestSource(r'''
foo(p) {}
class A {
@@ -702,21 +702,21 @@
A() : f = foo(() async {^});
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
}
- test_function_body_inClass_field() {
+ test_function_body_inClass_field() async {
addTestSource(r'''
class A {
var f = () {^};
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_function_body_inClass_methodBody() {
+ test_function_body_inClass_methodBody() async {
addTestSource(r'''
class A {
m() {
@@ -724,11 +724,11 @@
}
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_function_body_inClass_methodBody_inFunction() {
+ test_function_body_inClass_methodBody_inFunction() async {
addTestSource(r'''
class A {
m() {
@@ -738,11 +738,11 @@
}
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_function_body_inClass_methodBody_inFunction_async() {
+ test_function_body_inClass_methodBody_inFunction_async() async {
addTestSource(r'''
class A {
m() {
@@ -752,657 +752,659 @@
}
}
''');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
}
- test_function_body_inUnit() {
+ test_function_body_inUnit() async {
addTestSource('main() {^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_function_body_inUnit_afterBlock() {
+ test_function_body_inUnit_afterBlock() async {
addTestSource('main() {{}^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_function_body_inUnit_async() {
+ test_function_body_inUnit_async() async {
addTestSource('main() async {^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
}
- test_if_expression_in_class() {
+ test_if_expression_in_class() async {
addTestSource('class A {foo() {if (^) }}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_if_expression_in_class2() {
+ test_if_expression_in_class2() async {
addTestSource('class A {foo() {if (n^) }}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_if_expression_in_function() {
+ test_if_expression_in_function() async {
addTestSource('foo() {if (^) }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_if_expression_in_function2() {
+ test_if_expression_in_function2() async {
addTestSource('foo() {if (n^) }');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_if_in_class() {
+ test_if_in_class() async {
addTestSource('class A {foo() {if (true) ^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_if_in_class2() {
+ test_if_in_class2() async {
addTestSource('class A {foo() {if (true) ^;}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_if_in_class3() {
+ test_if_in_class3() async {
addTestSource('class A {foo() {if (true) r^;}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_if_in_class4() {
+ test_if_in_class4() async {
addTestSource('class A {foo() {if (true) ^ go();}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_if_outside_class() {
+ test_if_outside_class() async {
addTestSource('foo() {if (true) ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_if_outside_class2() {
+ test_if_outside_class2() async {
addTestSource('foo() {if (true) ^;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_if_outside_class3() {
+ test_if_outside_class3() async {
addTestSource('foo() {if (true) r^;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_if_outside_class4() {
+ test_if_outside_class4() async {
addTestSource('foo() {if (true) ^ go();}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS);
}
- test_import() {
+ test_import() async {
addTestSource('import "foo" deferred as foo ^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['show', 'hide'], relevance: DART_RELEVANCE_HIGH);
}
- test_import_as() {
+ test_import_as() async {
addTestSource('import "foo" deferred ^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
}
- test_import_as2() {
+ test_import_as2() async {
addTestSource('import "foo" deferred a^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
}
- test_import_as3() {
+ test_import_as3() async {
addTestSource('import "foo" deferred a^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred() {
+ test_import_deferred() async {
addTestSource('import "foo" ^ as foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred2() {
+ test_import_deferred2() async {
addTestSource('import "foo" d^ as foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred3() {
+ test_import_deferred3() async {
addTestSource('import "foo" d^ show foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as'], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred4() {
+ test_import_deferred4() async {
addTestSource('import "foo" d^ hide foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as'], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred5() {
+ test_import_deferred5() async {
addTestSource('import "foo" d^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred6() {
+ test_import_deferred6() async {
addTestSource('import "foo" d^ import');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_as() {
+ test_import_deferred_as() async {
addTestSource('import "foo" ^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_as2() {
+ test_import_deferred_as2() async {
addTestSource('import "foo" d^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_as3() {
+ test_import_deferred_as3() async {
addTestSource('import "foo" ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_as4() {
+ test_import_deferred_as4() async {
addTestSource('import "foo" d^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_as5() {
+ test_import_deferred_as5() async {
addTestSource('import "foo" sh^ import "bar"; import "baz";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.AS],
pseudoKeywords: ['deferred as', 'show', 'hide'],
relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_not() {
+ test_import_deferred_not() async {
addTestSource('import "foo" as foo ^;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['show', 'hide'], relevance: DART_RELEVANCE_HIGH);
}
- test_import_deferred_partial() {
+ test_import_deferred_partial() async {
addTestSource('import "package:foo/foo.dart" def^ as foo;');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 30);
+ expect(replacementLength, 3);
assertSuggestKeywords([Keyword.DEFERRED], relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 30);
- expect(request.replacementLength, 3);
+ expect(suggestions[0].selectionOffset, 8);
+ expect(suggestions[0].selectionLength, 0);
}
- test_import_incomplete() {
+ test_import_incomplete() async {
addTestSource('import "^"');
- expect(computeFast(), isTrue);
- assertNoSuggestions();
+ await computeSuggestions();
+ expect(suggestions, isEmpty);
}
- test_import_partial() {
+ test_import_partial() async {
addTestSource('imp^ import "package:foo/foo.dart"; import "bar.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 0);
+ expect(replacementLength, 3);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 0);
- expect(request.replacementLength, 3);
}
- test_import_partial2() {
+ test_import_partial2() async {
addTestSource('^imp import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 0);
+ expect(replacementLength, 3);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 0);
- expect(request.replacementLength, 3);
}
- test_import_partial3() {
+ test_import_partial3() async {
addTestSource(' ^imp import "package:foo/foo.dart"; import "bar.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 1);
+ expect(replacementLength, 3);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 1);
- expect(request.replacementLength, 3);
}
- test_import_partial4() {
+ test_import_partial4() async {
addTestSource('^ imp import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 0);
+ expect(replacementLength, 0);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 0);
- expect(request.replacementLength, 0);
}
- test_import_partial5() {
+ test_import_partial5() async {
addTestSource('library libA; imp^ import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 14);
+ expect(replacementLength, 3);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 14);
- expect(request.replacementLength, 3);
}
- test_import_partial6() {
+ test_import_partial6() async {
addTestSource(
'library bar; import "zoo.dart"; imp^ import "package:foo/foo.dart";');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 32);
+ expect(replacementLength, 3);
// TODO(danrubel) should not suggest declaration keywords
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 32);
- expect(request.replacementLength, 3);
}
- test_inComment_block() {
+ test_inComment_block() async {
addTestSource('''
main() {
/* text ^ */
print(42);
}
''');
- expect(computeFast(), isTrue);
- assertNoSuggestions();
+ await computeSuggestions();
+ expect(suggestions, isEmpty);
}
- test_inComment_endOfLine() {
+ test_inComment_endOfLine() async {
addTestSource('''
main() {
// text ^
}
''');
- expect(computeFast(), isTrue);
- assertNoSuggestions();
+ await computeSuggestions();
+ expect(suggestions, isEmpty);
}
- test_is_expression() {
+ test_is_expression() async {
addTestSource('main() {if (x is^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.IS], relevance: DART_RELEVANCE_HIGH);
}
- test_library() {
+ test_library() async {
addTestSource('library foo;^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_library_declaration() {
+ test_library_declaration() async {
addTestSource('library ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_library_declaration2() {
+ test_library_declaration2() async {
addTestSource('library a^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_library_declaration3() {
+ test_library_declaration3() async {
addTestSource('library a.^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_library_name() {
+ test_library_name() async {
addTestSource('library ^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_method_async() {
+ test_method_async() async {
addTestSource('class A { foo() ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_async2() {
+ test_method_async2() async {
addTestSource('class A { foo() ^{}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_method_async3() {
+ test_method_async3() async {
addTestSource('class A { foo() a^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_async4() {
+ test_method_async4() async {
addTestSource('class A { foo() a^{}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_async5() {
+ test_method_async5() async {
addTestSource('class A { foo() ^ Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_async6() {
+ test_method_async6() async {
addTestSource('class A { foo() a^ Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_async7() {
+ test_method_async7() async {
addTestSource('class A { foo() ^ => Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([],
pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
}
- test_method_async8() {
+ test_method_async8() async {
addTestSource('class A { foo() a^ Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
}
- test_method_body() {
+ test_method_body() async {
addTestSource('class A { foo() {^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS);
}
- test_method_body2() {
+ test_method_body2() async {
addTestSource('class A { foo() => ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_body3() {
+ test_method_body3() async {
addTestSource('class A { foo() => ^ Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_body4() {
+ test_method_body4() async {
addTestSource('class A { foo() => ^;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_body_async() {
+ test_method_body_async() async {
addTestSource('class A { foo() async {^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
}
- test_method_body_async2() {
+ test_method_body_async2() async {
addTestSource('class A { foo() async => ^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
}
- test_method_body_async3() {
+ test_method_body_async3() async {
addTestSource('class A { foo() async => ^ Foo foo;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
}
- test_method_body_async4() {
+ test_method_body_async4() async {
addTestSource('class A { foo() async => ^;}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE, pseudoKeywords: ['await']);
}
- test_method_body_expression1() {
+ test_method_body_expression1() async {
addTestSource('class A { foo() {return b == true ? ^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_body_expression2() {
+ test_method_body_expression2() async {
addTestSource('class A { foo() {return b == true ? 1 : ^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_body_return() {
+ test_method_body_return() async {
addTestSource('class A { foo() {return ^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_INSTANCE);
}
- test_method_param() {
+ test_method_param() async {
addTestSource('class A { foo(^) {});}');
- expect(computeFast(), isTrue);
- assertNoSuggestions();
+ await computeSuggestions();
+ expect(suggestions, isEmpty);
}
- test_method_param2() {
+ test_method_param2() async {
addTestSource('class A { foo(t^) {});}');
- expect(computeFast(), isTrue);
- assertNoSuggestions();
+ await computeSuggestions();
+ expect(suggestions, isEmpty);
}
- test_named_constructor_invocation() {
+ test_named_constructor_invocation() async {
addTestSource('void main() {new Future.^}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_newInstance() {
+ test_newInstance() async {
addTestSource('class A { foo() {new ^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_newInstance2() {
+ test_newInstance2() async {
addTestSource('class A { foo() {new ^ print("foo");}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_newInstance_prefixed() {
+ test_newInstance_prefixed() async {
addTestSource('class A { foo() {new A.^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_newInstance_prefixed2() {
+ test_newInstance_prefixed2() async {
addTestSource('class A { foo() {new A.^ print("foo");}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_part_of() {
+ test_part_of() async {
addTestSource('part of foo;^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_partial_class() {
+ test_partial_class() async {
addTestSource('cl^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_DECLARATION_AND_LIBRARY_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_partial_class2() {
+ test_partial_class2() async {
addTestSource('library a; cl^');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(DIRECTIVE_AND_DECLARATION_KEYWORDS,
relevance: DART_RELEVANCE_HIGH);
}
- test_prefixed_field() {
+ test_prefixed_field() async {
addTestSource('class A { int x; foo() {x.^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_prefixed_field2() {
+ test_prefixed_field2() async {
addTestSource('class A { int x; foo() {x.^ print("foo");}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_prefixed_library() {
+ test_prefixed_library() async {
addTestSource('import "b" as b; class A { foo() {b.^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_prefixed_local() {
+ test_prefixed_local() async {
addTestSource('class A { foo() {int x; x.^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_prefixed_local2() {
+ test_prefixed_local2() async {
addTestSource('class A { foo() {int x; x.^ print("foo");}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_property_access() {
+ test_property_access() async {
addTestSource('class A { get x => 7; foo() {new A().^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([]);
}
- test_switch_expression() {
+ test_switch_expression() async {
addTestSource('main() {switch(^) {}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_switch_expression2() {
+ test_switch_expression2() async {
addTestSource('main() {switch(n^) {}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_switch_expression3() {
+ test_switch_expression3() async {
addTestSource('main() {switch(n^)}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE);
}
- test_switch_start() {
+ test_switch_start() async {
addTestSource('main() {switch(1) {^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
}
- test_switch_start2() {
+ test_switch_start2() async {
addTestSource('main() {switch(1) {^ case 1:}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
}
- test_switch_start3() {
+ test_switch_start3() async {
addTestSource('main() {switch(1) {^default:}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
}
- test_switch_start4() {
+ test_switch_start4() async {
addTestSource('main() {switch(1) {^ default:}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
}
- test_switch_start5() {
+ test_switch_start5() async {
addTestSource('main() {switch(1) {c^ default:}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 19);
+ expect(replacementLength, 1);
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 19);
- expect(request.replacementLength, 1);
}
- test_switch_start6() {
+ test_switch_start6() async {
addTestSource('main() {switch(1) {c^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 19);
+ expect(replacementLength, 1);
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 19);
- expect(request.replacementLength, 1);
}
- test_switch_start7() {
+ test_switch_start7() async {
addTestSource('main() {switch(1) { c^ }}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
+ expect(replacementOffset, 20);
+ expect(replacementLength, 1);
assertSuggestKeywords([Keyword.CASE, Keyword.DEFAULT],
relevance: DART_RELEVANCE_HIGH);
- expect(request.replacementOffset, 20);
- expect(request.replacementLength, 1);
}
- test_switch_statement() {
+ test_switch_statement() async {
addTestSource('main() {switch(1) {case 1:^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_SWITCH_OUTSIDE_CLASS);
}
- test_switch_statement2() {
+ test_switch_statement2() async {
addTestSource('class A{foo() {switch(1) {case 1:^}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_SWITCH_IN_CLASS);
}
- test_while_break_continue() {
+ test_while_break_continue() async {
addTestSource('main() {while (true) {^}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_OUTSIDE_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
- test_while_break_continue2() {
+ test_while_break_continue2() async {
addTestSource('class A {foo() {while (true) {^}}}');
- expect(computeFast(), isTrue);
+ await computeSuggestions();
assertSuggestKeywords(STMT_START_IN_LOOP_IN_CLASS,
relevance: DART_RELEVANCE_KEYWORD);
}
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
new file mode 100644
index 0000000..9d8d061
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.completion.dart;
+
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'combinator_contributor_test.dart' as combinator_test;
+import 'arglist_contributor_test.dart' as arglist_test;
+import 'common_usage_sorter_test.dart' as common_usage_test;
+import 'inherited_contributor_test.dart' as inherited_contributor_test;
+import 'keyword_contributor_test.dart' as keyword_test;
+import 'uri_contributor_test.dart' as uri_contributor_test;
+
+/// Utility for manually running all tests.
+main() {
+ initializeTestEnvironment();
+ group('dart/completion', () {
+ arglist_test.main();
+ combinator_test.main();
+ common_usage_test.main();
+ inherited_contributor_test.main();
+ keyword_test.main();
+ uri_contributor_test.main();
+ });
+}
diff --git a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
similarity index 73%
rename from pkg/analysis_server/test/services/completion/uri_contributor_test.dart
rename to pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
index 22ebe15..e6c2384 100644
--- a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/uri_contributor_test.dart
@@ -5,15 +5,15 @@
library test.services.completion.contributor.dart.importuri;
import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/uri_contributor.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:path/path.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
-import '../../utils.dart';
-import 'completion_test_util.dart';
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
main() {
initializeTestEnvironment();
@@ -22,85 +22,85 @@
}
@reflectiveTest
-class UriContributorTest extends AbstractCompletionTest {
+class UriContributorTest extends DartCompletionContributorTest {
@override
- void setUpContributor() {
- contributor = new UriContributor();
+ DartCompletionContributor createContributor() {
+ return new UriContributor();
}
- test_after_import() {
+ test_after_import() async {
addTestSource('import "p"^');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNoSuggestions();
}
- test_after_import_raw() {
+ test_after_import_raw() async {
addTestSource('import r"p"^');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNoSuggestions();
}
- test_before_import() {
+ test_before_import() async {
addTestSource('import ^"p"');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNoSuggestions();
}
- test_before_import_raw() {
+ test_before_import_raw() async {
addTestSource('import ^r"p"');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNoSuggestions();
}
- test_before_import_raw2() {
+ test_before_import_raw2() async {
addTestSource('import r^"p"');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNoSuggestions();
}
- test_export_package2() {
+ test_export_package2() async {
addPackageSource('foo', 'foo.dart', 'library foo;');
addPackageSource('foo', 'baz/too.dart', 'library too;');
addPackageSource('bar', 'bar.dart', 'library bar;');
addTestSource('export "package:foo/baz/^" import');
- computeFast();
+ await computeSuggestions();
assertSuggest('package:foo/baz/too.dart',
csKind: CompletionSuggestionKind.IMPORT);
}
- test_import() {
+ test_import() async {
addTestSource('import "^"');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import2() {
+ test_import2() async {
addTestSource('import "^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_dart() {
+ test_import_dart() async {
addTestSource('import "d^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 1);
- expect(request.replacementLength, 1);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('dart:core',
csKind: CompletionSuggestionKind.IMPORT, relevance: DART_RELEVANCE_LOW);
@@ -109,11 +109,11 @@
assertSuggest('dart:math', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_dart2() {
+ test_import_dart2() async {
addTestSource('import "dart:async"; import "d^"');
- computeFast();
- expect(request.replacementOffset, completionOffset - 1);
- expect(request.replacementLength, 1);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('dart:core',
csKind: CompletionSuggestionKind.IMPORT, relevance: DART_RELEVANCE_LOW);
@@ -122,15 +122,15 @@
assertSuggest('dart:math', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_file() {
+ test_import_file() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('import "^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -139,15 +139,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file2() {
+ test_import_file2() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('import "..^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 2);
- expect(request.replacementLength, 2);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 2);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -156,15 +156,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file_child() {
+ test_import_file_child() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('import "foo/^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -173,15 +173,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file_parent() {
+ test_import_file_parent() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('import "../^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 3);
- expect(request.replacementLength, 3);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -190,15 +190,15 @@
assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_file_parent2() {
+ test_import_file_parent2() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('import "../b^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -207,14 +207,14 @@
assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_package() {
+ test_import_package() async {
addPackageSource('foo', 'foo.dart', 'library foo;');
addPackageSource('foo', 'baz/too.dart', 'library too;');
addPackageSource('bar', 'bar.dart', 'library bar;');
addTestSource('import "p^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 1);
- expect(request.replacementLength, 1);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:foo/', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:foo/foo.dart',
@@ -226,46 +226,46 @@
csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_package2() {
+ test_import_package2() async {
addPackageSource('foo', 'foo.dart', 'library foo;');
addPackageSource('foo', 'baz/too.dart', 'library too;');
addPackageSource('bar', 'bar.dart', 'library bar;');
addTestSource('import "package:foo/baz/^" import');
- computeFast();
+ await computeSuggestions();
assertSuggest('package:foo/baz/too.dart',
csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_package2_raw() {
+ test_import_package2_raw() async {
addPackageSource('foo', 'foo.dart', 'library foo;');
addPackageSource('foo', 'baz/too.dart', 'library too;');
addPackageSource('bar', 'bar.dart', 'library bar;');
addTestSource('import r"package:foo/baz/^" import');
- computeFast();
+ await computeSuggestions();
assertSuggest('package:foo/baz/too.dart',
csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_package_missing_lib() {
+ test_import_package_missing_lib() async {
var pkgSrc = addPackageSource('bar', 'bar.dart', 'library bar;');
provider.deleteFolder(dirname(pkgSrc.fullName));
addTestSource('import "p^" class');
- computeFast();
- expect(request.replacementOffset, completionOffset - 1);
- expect(request.replacementLength, 1);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:bar/', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('package:bar/bar.dart');
}
- test_import_package_raw() {
+ test_import_package_raw() async {
addPackageSource('foo', 'foo.dart', 'library foo;');
addPackageSource('foo', 'baz/too.dart', 'library too;');
addPackageSource('bar', 'bar.dart', 'library bar;');
addTestSource('import r"p^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 1);
- expect(request.replacementLength, 1);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:foo/', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:foo/foo.dart',
@@ -277,40 +277,36 @@
csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_raw() {
+ test_import_raw() async {
addTestSource('import r"^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertSuggest('dart:', csKind: CompletionSuggestionKind.IMPORT);
assertSuggest('package:', csKind: CompletionSuggestionKind.IMPORT);
}
- test_outside_import() {
+ test_outside_import() async {
addTestSource('import ^"d" import');
- computeFast();
- computeFull((_) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_outside_import2() {
+ test_outside_import2() async {
addTestSource('import "d"^ import');
- computeFast();
- computeFull((_) {
- assertNoSuggestions();
- });
+ await computeSuggestions();
+ assertNoSuggestions();
}
- test_part_file() {
+ test_part_file() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('library x; part "^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -319,15 +315,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file2() {
+ test_part_file2() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('library x; part "..^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 2);
- expect(request.replacementLength, 2);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 2);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -336,15 +332,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file_child() {
+ test_part_file_child() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('library x; part "foo/^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -353,15 +349,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file_parent() {
+ test_part_file_parent() async {
testFile = '/proj/completion.dart';
addSource('/proj/other.dart', 'library other;');
addSource('/proj/foo/bar.dart', 'library bar;');
addSource('/blat.dart', 'library blat;');
addTestSource('library x; part "../^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 3);
- expect(request.replacementLength, 3);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -372,10 +368,10 @@
}
@reflectiveTest
-class UriContributorWindowsTest extends AbstractCompletionTest {
+class UriContributorWindowsTest extends DartCompletionContributorTest {
@override
- void setUpContributor() {
- contributor = new UriContributor();
+ DartCompletionContributor createContributor() {
+ return new UriContributor();
}
@override
@@ -383,15 +379,15 @@
provider = new _TestWinResourceProvider();
}
- test_import_file() {
+ test_import_file() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('import "^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -400,15 +396,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file2() {
+ test_import_file2() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('import "..^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 2);
- expect(request.replacementLength, 2);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 2);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -417,15 +413,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file_child() {
+ test_import_file_child() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('import "foo/^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -434,15 +430,15 @@
assertNotSuggested('../blat.dart');
}
- test_import_file_parent() {
+ test_import_file_parent() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('import "../^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 3);
- expect(request.replacementLength, 3);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -451,15 +447,15 @@
assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
}
- test_import_file_parent2() {
+ test_import_file_parent2() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('import "../b^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -468,15 +464,15 @@
assertSuggest('../blat.dart', csKind: CompletionSuggestionKind.IMPORT);
}
- test_part_file() {
+ test_part_file() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('library x; part "^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset);
- expect(request.replacementLength, 0);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -485,15 +481,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file2() {
+ test_part_file2() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('library x; part "..^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 2);
- expect(request.replacementLength, 2);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 2);
assertNotSuggested('completion.dart');
assertSuggest('other.dart', csKind: CompletionSuggestionKind.IMPORT);
assertNotSuggested('foo');
@@ -502,15 +498,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file_child() {
+ test_part_file_child() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('library x; part "foo/^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 4);
- expect(request.replacementLength, 4);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 4);
+ expect(replacementLength, 4);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
@@ -519,15 +515,15 @@
assertNotSuggested('../blat.dart');
}
- test_part_file_parent() {
+ test_part_file_parent() async {
testFile = '\\proj\\completion.dart';
addSource('\\proj\\other.dart', 'library other;');
addSource('\\proj\\foo\\bar.dart', 'library bar;');
addSource('\\blat.dart', 'library blat;');
addTestSource('library x; part "../^" import');
- computeFast();
- expect(request.replacementOffset, completionOffset - 3);
- expect(request.replacementLength, 3);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
assertNotSuggested('completion.dart');
assertNotSuggested('other.dart');
assertNotSuggested('foo');
diff --git a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
index 95cbb70..54ad5e1 100644
--- a/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_reference_contributor_test.dart
@@ -8,7 +8,6 @@
show Element, ElementKind;
import 'package:analysis_server/plugin/protocol/protocol.dart'
hide Element, ElementKind;
-import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -20,7 +19,6 @@
import 'package:unittest/unittest.dart';
import '../../abstract_context.dart';
-import '../../operation/operation_queue_test.dart';
import '../../utils.dart';
import 'completion_test_util.dart';
@@ -64,13 +62,12 @@
setUpContributor();
int replacementOffset = request.replacementOffset;
int replacementLength = request.replacementLength;
- AnalysisServer server = new AnalysisServerMock();
/*
* Pass null for searchEngine to ensure that it is not used
* when the cache has been populated.
*/
request = new DartCompletionRequest(
- server, context, testSource, completionOffset, cache);
+ context, provider, searchEngine, testSource, completionOffset, cache);
request.replacementOffset = replacementOffset;
request.replacementLength = replacementLength;
diff --git a/pkg/analysis_server/test/services/completion/inherited_computer_test.dart b/pkg/analysis_server/test/services/completion/inherited_computer_test.dart
deleted file mode 100644
index a50fa2f..0000000
--- a/pkg/analysis_server/test/services/completion/inherited_computer_test.dart
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library test.services.completion.inherited_computer_test;
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/inherited_contributor.dart';
-import 'package:test_reflective_loader/test_reflective_loader.dart';
-import 'package:unittest/src/matcher/core_matchers.dart';
-import 'package:unittest/unittest.dart';
-
-import '../../utils.dart';
-import 'completion_test_util.dart';
-
-main() {
- initializeTestEnvironment();
-// defineReflectiveTests(InheritedContributorTest);
-}
-
-@reflectiveTest
-class InheritedContributorTest extends AbstractCompletionTest {
- @override
- void setUpContributor() {
- contributor = new NewCompletionWrapper(new InheritedContributor());
- }
-
- test_fromMultipleSuperclasses() {
- addTestSource(r'''
-class A {
- notSuggested() => null;
- A suggested1(int x) => null;
- B suggested2(String y) => null;
-}
-class B extends A {
- B suggested2(String y) => null;
- C suggested3([String z]) => null;
-}
-class C extends B {
- sugg^
-}
-''');
- computeFast();
- return computeFull((bool result) {
- _assertOverride(
- '@override\n A suggested1(int x) {\n // TODO: implement suggested1\n return null;\n }');
- _assertOverride(
- '''@override\n B suggested2(String y) {\n // TODO: implement suggested2\n return null;\n }''');
- _assertOverride(
- '''@override\n C suggested3([String z]) {\n // TODO: implement suggested3\n return null;\n }''');
- assertNotSuggested(
- '''@override\n notSuggested() {\n // TODO: implement notSuggested\n return null;\n }''');
- });
- }
-
- CompletionSuggestion _assertOverride(String completion) {
- CompletionSuggestion cs = getSuggest(
- completion: completion,
- csKind: CompletionSuggestionKind.IDENTIFIER,
- elemKind: null);
- if (cs == null) {
- failedCompletion('expected $completion', request.suggestions);
- }
- expect(cs.kind, equals(CompletionSuggestionKind.IDENTIFIER));
- expect(cs.relevance, equals(DART_RELEVANCE_HIGH));
- expect(cs.importUri, null);
-// expect(cs.selectionOffset, equals(completion.length));
- expect(cs.selectionLength, equals(0));
- expect(cs.isDeprecated, isFalse);
- expect(cs.isPotential, isFalse);
- expect(cs.element, isNotNull);
- return cs;
- }
-}
diff --git a/pkg/analysis_server/test/services/completion/test_all.dart b/pkg/analysis_server/test/services/completion/test_all.dart
index 69735da..c4adeb2 100644
--- a/pkg/analysis_server/test/services/completion/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/test_all.dart
@@ -7,39 +7,29 @@
import 'package:unittest/unittest.dart';
import '../../utils.dart';
-import 'arglist_contributor_test.dart' as arglist_test;
-import 'combinator_contributor_test.dart' as combinator_test;
-import 'common_usage_computer_test.dart' as common_usage_computer_test;
import 'completion_computer_test.dart' as completion_computer_test;
import 'completion_manager_test.dart' as completion_manager_test;
import 'completion_target_test.dart' as completion_target_test;
+import 'dart/test_all.dart' as dart_contributor_tests;
import 'imported_reference_contributor_test.dart' as imported_test;
-import 'inherited_computer_test.dart' as inherited_computer_test;
-import 'keyword_contributor_test.dart' as keyword_test;
import 'local_declaration_visitor_test.dart' as local_declaration_visitor_test;
import 'local_reference_contributor_test.dart'
as local_reference_contributor_test;
import 'optype_test.dart' as optype_test;
import 'prefixed_element_contributor_test.dart' as invocation_test;
-import 'uri_contributor_test.dart' as uri_contributor_test;
/// Utility for manually running all tests.
main() {
initializeTestEnvironment();
group('completion', () {
- arglist_test.main();
- combinator_test.main();
- common_usage_computer_test.main();
completion_computer_test.main();
completion_manager_test.main();
completion_target_test.main();
+ dart_contributor_tests.main();
imported_test.main();
- inherited_computer_test.main();
invocation_test.main();
- keyword_test.main();
local_declaration_visitor_test.main();
local_reference_contributor_test.main();
optype_test.main();
- uri_contributor_test.main();
});
}
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 2885f27..48e8068 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -4,6 +4,8 @@
library test.services.correction.assist;
+import 'dart:async';
+
import 'package:analysis_server/plugin/edit/assist/assist_core.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/plugin/server_plugin.dart';
@@ -36,8 +38,8 @@
* Asserts that there is an [Assist] of the given [kind] at [offset] which
* produces the [expected] code when applied to [testCode].
*/
- void assertHasAssist(AssistKind kind, String expected) {
- assist = _assertHasAssist(kind);
+ assertHasAssist(AssistKind kind, String expected) async {
+ assist = await _assertHasAssist(kind);
change = assist.change;
// apply to "file"
List<SourceFileEdit> fileEdits = change.edits;
@@ -50,17 +52,17 @@
/**
* Calls [assertHasAssist] at the offset of [offsetSearch] in [testCode].
*/
- void assertHasAssistAt(
- String offsetSearch, AssistKind kind, String expected) {
+ assertHasAssistAt(
+ String offsetSearch, AssistKind kind, String expected) async {
offset = findOffset(offsetSearch);
- assertHasAssist(kind, expected);
+ await assertHasAssist(kind, expected);
}
/**
* Asserts that there is no [Assist] of the given [kind] at [offset].
*/
- void assertNoAssist(AssistKind kind) {
- List<Assist> assists = computeAssists(
+ assertNoAssist(AssistKind kind) async {
+ List<Assist> assists = await computeAssists(
plugin, context, testUnit.element.source, offset, length);
for (Assist assist in assists) {
if (assist.kind == kind) {
@@ -72,9 +74,9 @@
/**
* Calls [assertNoAssist] at the offset of [offsetSearch] in [testCode].
*/
- void assertNoAssistAt(String offsetSearch, AssistKind kind) {
+ assertNoAssistAt(String offsetSearch, AssistKind kind) async {
offset = findOffset(offsetSearch);
- assertNoAssist(kind);
+ await assertNoAssist(kind);
}
Position expectedPosition(String search) {
@@ -106,7 +108,7 @@
manager.processPlugins([plugin]);
}
- void test_addTypeAnnotation_BAD_privateType_closureParameter() {
+ test_addTypeAnnotation_BAD_privateType_closureParameter() async {
addSource(
'/my_lib.dart',
'''
@@ -121,10 +123,10 @@
foo((test) {});
}
''');
- assertNoAssistAt('test)', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('test)', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_BAD_privateType_declaredIdentifier() {
+ test_addTypeAnnotation_BAD_privateType_declaredIdentifier() async {
addSource(
'/my_lib.dart',
'''
@@ -142,10 +144,10 @@
}
}
''');
- assertNoAssistAt('var item', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('var item', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_BAD_privateType_list() {
+ test_addTypeAnnotation_BAD_privateType_list() async {
addSource(
'/my_lib.dart',
'''
@@ -160,10 +162,10 @@
var v = getValues();
}
''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_BAD_privateType_variable() {
+ test_addTypeAnnotation_BAD_privateType_variable() async {
addSource(
'/my_lib.dart',
'''
@@ -178,16 +180,16 @@
var v = getValue();
}
''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_classField_OK_final() {
+ test_addTypeAnnotation_classField_OK_final() async {
resolveTestUnit('''
class A {
final f = 0;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'final ',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -197,13 +199,13 @@
''');
}
- void test_addTypeAnnotation_classField_OK_int() {
+ test_addTypeAnnotation_classField_OK_int() async {
resolveTestUnit('''
class A {
var f = 0;
}
''');
- assertHasAssistAt(
+ await await assertHasAssistAt(
'var ',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -213,17 +215,17 @@
''');
}
- void test_addTypeAnnotation_declaredIdentifier_BAD_hasTypeAnnotation() {
+ test_addTypeAnnotation_declaredIdentifier_BAD_hasTypeAnnotation() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
}
}
''');
- assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_declaredIdentifier_BAD_inForEachBody() {
+ test_addTypeAnnotation_declaredIdentifier_BAD_inForEachBody() async {
resolveTestUnit('''
main(List<String> items) {
for (var item in items) {
@@ -231,10 +233,10 @@
}
}
''');
- assertNoAssistAt('42;', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('42;', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_declaredIdentifier_BAD_unknownType() {
+ test_addTypeAnnotation_declaredIdentifier_BAD_unknownType() async {
verifyNoTestUnitErrors = false;
resolveTestUnit('''
main() {
@@ -242,10 +244,10 @@
}
}
''');
- assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('item in', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_declaredIdentifier_generic_OK() {
+ test_addTypeAnnotation_declaredIdentifier_generic_OK() async {
resolveTestUnit('''
class A<T> {
main(List<List<T>> items) {
@@ -254,7 +256,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'item in',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -267,7 +269,7 @@
''');
}
- void test_addTypeAnnotation_declaredIdentifier_OK() {
+ test_addTypeAnnotation_declaredIdentifier_OK() async {
resolveTestUnit('''
main(List<String> items) {
for (var item in items) {
@@ -275,7 +277,7 @@
}
''');
// on identifier
- assertHasAssistAt(
+ await assertHasAssistAt(
'item in',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -285,7 +287,7 @@
}
''');
// on "for"
- assertHasAssistAt(
+ await assertHasAssistAt(
'for (',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -296,7 +298,7 @@
''');
}
- void test_addTypeAnnotation_declaredIdentifier_OK_addImport_dartUri() {
+ test_addTypeAnnotation_declaredIdentifier_OK_addImport_dartUri() async {
addSource(
'/my_lib.dart',
r'''
@@ -310,7 +312,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'future in',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -323,14 +325,14 @@
''');
}
- void test_addTypeAnnotation_declaredIdentifier_OK_final() {
+ test_addTypeAnnotation_declaredIdentifier_OK_final() async {
resolveTestUnit('''
main(List<String> items) {
for (final item in items) {
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'item in',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -341,7 +343,54 @@
''');
}
- void test_addTypeAnnotation_local_generic_OK_literal() {
+ test_addTypeAnnotation_local_BAD_hasTypeAnnotation() async {
+ resolveTestUnit('''
+main() {
+ int v = 42;
+}
+''');
+ await assertNoAssistAt(' = 42', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_local_BAD_multiple() async {
+ resolveTestUnit('''
+main() {
+ var a = 1, b = '';
+}
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_local_BAD_noValue() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ var v;
+}
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_local_BAD_null() async {
+ resolveTestUnit('''
+main() {
+ var v = null;
+}
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_local_BAD_unknown() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ var v = unknownVar;
+}
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_local_generic_OK_literal() async {
resolveTestUnit('''
class A {
main(List<int> items) {
@@ -349,7 +398,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -361,7 +410,7 @@
''');
}
- void test_addTypeAnnotation_local_generic_OK_local() {
+ test_addTypeAnnotation_local_generic_OK_local() async {
resolveTestUnit('''
class A<T> {
main(List<T> items) {
@@ -369,7 +418,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -381,7 +430,7 @@
''');
}
- void test_addTypeAnnotation_local_OK_addImport_dartUri() {
+ test_addTypeAnnotation_local_OK_addImport_dartUri() async {
addSource(
'/my_lib.dart',
r'''
@@ -394,7 +443,7 @@
var v = getFutureInt();
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -406,7 +455,7 @@
''');
}
- void test_addTypeAnnotation_local_OK_addImport_notLibraryUnit() {
+ test_addTypeAnnotation_local_OK_addImport_notLibraryUnit() async {
// prepare library
addSource(
'/my_lib.dart',
@@ -437,7 +486,7 @@
testLibraryElement = testUnitElement.library;
// prepare the assist
offset = findOffset('v = ');
- assist = _assertHasAssist(DartAssistKind.ADD_TYPE_ANNOTATION);
+ assist = await _assertHasAssist(DartAssistKind.ADD_TYPE_ANNOTATION);
change = assist.change;
// verify
{
@@ -466,7 +515,7 @@
}
}
- void test_addTypeAnnotation_local_OK_addImport_relUri() {
+ test_addTypeAnnotation_local_OK_addImport_relUri() async {
addSource(
'/aa/bbb/lib_a.dart',
r'''
@@ -484,7 +533,7 @@
var v = newMyClass();
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -496,13 +545,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_Function() {
+ test_addTypeAnnotation_local_OK_Function() async {
resolveTestUnit('''
main() {
var v = () => 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -512,13 +561,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_int() {
+ test_addTypeAnnotation_local_OK_int() async {
resolveTestUnit('''
main() {
var v = 0;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -528,13 +577,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_List() {
+ test_addTypeAnnotation_local_OK_List() async {
resolveTestUnit('''
main() {
var v = <String>[];
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -544,7 +593,7 @@
''');
}
- void test_addTypeAnnotation_local_OK_localType() {
+ test_addTypeAnnotation_local_OK_localType() async {
resolveTestUnit('''
class C {}
C f() => null;
@@ -552,7 +601,7 @@
var x = f();
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'x =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -564,13 +613,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_onInitializer() {
+ test_addTypeAnnotation_local_OK_onInitializer() async {
resolveTestUnit('''
main() {
var v = 123;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'23',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -580,13 +629,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_onName() {
+ test_addTypeAnnotation_local_OK_onName() async {
resolveTestUnit('''
main() {
var abc = 0;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'bc',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -596,13 +645,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_onVar() {
+ test_addTypeAnnotation_local_OK_onVar() async {
resolveTestUnit('''
main() {
var v = 0;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'var ',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -612,13 +661,13 @@
''');
}
- void test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() {
+ test_addTypeAnnotation_local_OK_onVariableDeclarationStatement() async {
resolveTestUnit('''
main() {
var v = 123; // marker
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
' // marker',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -628,54 +677,7 @@
''');
}
- void test_addTypeAnnotation_local_wrong_hasTypeAnnotation() {
- resolveTestUnit('''
-main() {
- int v = 42;
-}
-''');
- assertNoAssistAt(' = 42', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_local_wrong_multiple() {
- resolveTestUnit('''
-main() {
- var a = 1, b = '';
-}
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_local_wrong_noValue() {
- verifyNoTestUnitErrors = false;
- resolveTestUnit('''
-main() {
- var v;
-}
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_local_wrong_null() {
- resolveTestUnit('''
-main() {
- var v = null;
-}
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_local_wrong_unknown() {
- verifyNoTestUnitErrors = false;
- resolveTestUnit('''
-main() {
- var v = unknownVar;
-}
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_OK_privateType_sameLibrary() {
+ test_addTypeAnnotation_OK_privateType_sameLibrary() async {
resolveTestUnit('''
class _A {}
_A getValue() => new _A();
@@ -683,7 +685,7 @@
var v = getValue();
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'var ',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -695,34 +697,34 @@
''');
}
- void test_addTypeAnnotation_parameter_BAD_hasExplicitType() {
+ test_addTypeAnnotation_parameter_BAD_hasExplicitType() async {
resolveTestUnit('''
foo(f(int p)) {}
main() {
foo((num test) {});
}
''');
- assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_parameter_BAD_noPropagatedType() {
+ test_addTypeAnnotation_parameter_BAD_noPropagatedType() async {
resolveTestUnit('''
foo(f(p)) {}
main() {
foo((test) {});
}
''');
- assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
+ await assertNoAssistAt('test', DartAssistKind.ADD_TYPE_ANNOTATION);
}
- void test_addTypeAnnotation_parameter_OK() {
+ test_addTypeAnnotation_parameter_OK() async {
resolveTestUnit('''
foo(f(int p)) {}
main() {
foo((test) {});
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -733,11 +735,25 @@
''');
}
- void test_addTypeAnnotation_topLevelField_OK_int() {
+ test_addTypeAnnotation_topLevelField_BAD_multiple() async {
+ resolveTestUnit('''
+var A = 1, V = '';
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_topLevelField_BAD_noValue() async {
+ resolveTestUnit('''
+var V;
+''');
+ await assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
+ }
+
+ test_addTypeAnnotation_topLevelField_OK_int() async {
resolveTestUnit('''
var V = 0;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'var ',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
@@ -745,21 +761,7 @@
''');
}
- void test_addTypeAnnotation_topLevelField_wrong_multiple() {
- resolveTestUnit('''
-var A = 1, V = '';
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_addTypeAnnotation_topLevelField_wrong_noValue() {
- resolveTestUnit('''
-var V;
-''');
- assertNoAssistAt('var ', DartAssistKind.ADD_TYPE_ANNOTATION);
- }
-
- void test_assignToLocalVariable() {
+ test_assignToLocalVariable() async {
resolveTestUnit('''
main() {
List<int> bytes;
@@ -767,7 +769,7 @@
}
List<int> readBytes() => <int>[];
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'readBytes();',
DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
'''
@@ -784,17 +786,17 @@
['list', 'bytes2', 'readBytes']));
}
- void test_assignToLocalVariable_alreadyAssignment() {
+ test_assignToLocalVariable_alreadyAssignment() async {
resolveTestUnit('''
main() {
var vvv;
vvv = 42;
}
''');
- assertNoAssistAt('vvv =', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+ await assertNoAssistAt('vvv =', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
}
- void test_assignToLocalVariable_inClosure() {
+ test_assignToLocalVariable_inClosure() async {
resolveTestUnit(r'''
main() {
print(() {
@@ -802,7 +804,7 @@
});
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'345',
DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE,
'''
@@ -814,42 +816,199 @@
''');
}
- void test_assignToLocalVariable_invocationArgument() {
+ test_assignToLocalVariable_invocationArgument() async {
resolveTestUnit(r'''
main() {
f(12345);
}
int f(p) {}
''');
- assertNoAssistAt('345', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+ await assertNoAssistAt('345', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
}
- void test_assignToLocalVariable_throw() {
+ test_assignToLocalVariable_throw() async {
resolveTestUnit('''
main() {
throw 42;
}
''');
- assertNoAssistAt('throw ', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+ await assertNoAssistAt('throw ', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
}
- void test_assignToLocalVariable_void() {
+ test_assignToLocalVariable_void() async {
resolveTestUnit('''
main() {
f();
}
void f() {}
''');
- assertNoAssistAt('f();', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
+ await assertNoAssistAt('f();', DartAssistKind.ASSIGN_TO_LOCAL_VARIABLE);
}
- void test_convertToBlockBody_OK_async() {
+ test_convertDocumentationIntoBlock_BAD_alreadyBlock() async {
+ resolveTestUnit('''
+/**
+ * AAAAAAA
+ */
+class A {}
+''');
+ await assertNoAssistAt(
+ 'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK);
+ }
+
+ test_convertDocumentationIntoBlock_BAD_notDocumentation() async {
+ resolveTestUnit('''
+// AAAA
+class A {}
+''');
+ await assertNoAssistAt(
+ 'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK);
+ }
+
+ test_convertDocumentationIntoBlock_OK_onReference() async {
+ resolveTestUnit('''
+/// AAAAAAA [int] AAAAAAA
+class A {}
+''');
+ await assertHasAssistAt(
+ 'nt]',
+ DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK,
+ '''
+/**
+ * AAAAAAA [int] AAAAAAA
+ */
+class A {}
+''');
+ }
+
+ test_convertDocumentationIntoBlock_OK_onText() async {
+ resolveTestUnit('''
+class A {
+ /// AAAAAAA [int] AAAAAAA
+ /// BBBBBBBB BBBB BBBB
+ /// CCC [A] CCCCCCCCCCC
+ mmm() {}
+}
+''');
+ await assertHasAssistAt(
+ 'AAA [',
+ DartAssistKind.CONVERT_DOCUMENTATION_INTO_BLOCK,
+ '''
+class A {
+ /**
+ * AAAAAAA [int] AAAAAAA
+ * BBBBBBBB BBBB BBBB
+ * CCC [A] CCCCCCCCCCC
+ */
+ mmm() {}
+}
+''');
+ }
+
+ test_convertDocumentationIntoLine_BAD_alreadyLine() async {
+ resolveTestUnit('''
+/// AAAAAAA
+class A {}
+''');
+ await assertNoAssistAt(
+ 'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
+ }
+
+ test_convertDocumentationIntoLine_BAD_notDocumentation() async {
+ resolveTestUnit('''
+/* AAAA */
+class A {}
+''');
+ await assertNoAssistAt(
+ 'AAA', DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE);
+ }
+
+ test_convertDocumentationIntoLine_OK_onReference() async {
+ resolveTestUnit('''
+/**
+ * AAAAAAA [int] AAAAAAA
+ */
+class A {}
+''');
+ await assertHasAssistAt(
+ 'nt]',
+ DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+ '''
+/// AAAAAAA [int] AAAAAAA
+class A {}
+''');
+ }
+
+ test_convertDocumentationIntoLine_OK_onText() async {
+ resolveTestUnit('''
+class A {
+ /**
+ * AAAAAAA [int] AAAAAAA
+ * BBBBBBBB BBBB BBBB
+ * CCC [A] CCCCCCCCCCC
+ */
+ mmm() {}
+}
+''');
+ await assertHasAssistAt(
+ 'AAA [',
+ DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+ '''
+class A {
+ /// AAAAAAA [int] AAAAAAA
+ /// BBBBBBBB BBBB BBBB
+ /// CCC [A] CCCCCCCCCCC
+ mmm() {}
+}
+''');
+ }
+
+ test_convertDocumentationIntoLine_OK_onText_hasFirstLine() async {
+ resolveTestUnit('''
+class A {
+ /** AAAAAAA [int] AAAAAAA
+ * BBBBBBBB BBBB BBBB
+ * CCC [A] CCCCCCCCCCC
+ */
+ mmm() {}
+}
+''');
+ await assertHasAssistAt(
+ 'AAA [',
+ DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE,
+ '''
+class A {
+ /// AAAAAAA [int] AAAAAAA
+ /// BBBBBBBB BBBB BBBB
+ /// CCC [A] CCCCCCCCCCC
+ mmm() {}
+}
+''');
+ }
+
+ test_convertToBlockBody_BAD_noEnclosingFunction() async {
+ resolveTestUnit('''
+var v = 123;
+''');
+ await assertNoAssistAt('v =', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+ }
+
+ test_convertToBlockBody_BAD_notExpressionBlock() async {
+ resolveTestUnit('''
+fff() {
+ return 123;
+}
+''');
+ await assertNoAssistAt('fff() {', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+ }
+
+ test_convertToBlockBody_OK_async() async {
resolveTestUnit('''
class A {
mmm() async => 123;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'mmm()',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -861,14 +1020,14 @@
''');
}
- void test_convertToBlockBody_OK_closure() {
+ test_convertToBlockBody_OK_closure() async {
resolveTestUnit('''
setup(x) {}
main() {
setup(() => 42);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'() => 42',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -887,14 +1046,14 @@
}
}
- void test_convertToBlockBody_OK_closure_voidExpression() {
+ test_convertToBlockBody_OK_closure_voidExpression() async {
resolveTestUnit('''
setup(x) {}
main() {
setup(() => print('done'));
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'() => print',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -913,13 +1072,13 @@
}
}
- void test_convertToBlockBody_OK_constructor() {
+ test_convertToBlockBody_OK_constructor() async {
resolveTestUnit('''
class A {
factory A() => null;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'A()',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -931,13 +1090,13 @@
''');
}
- void test_convertToBlockBody_OK_method() {
+ test_convertToBlockBody_OK_method() async {
resolveTestUnit('''
class A {
mmm() => 123;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'mmm()',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -949,11 +1108,11 @@
''');
}
- void test_convertToBlockBody_OK_onName() {
+ test_convertToBlockBody_OK_onName() async {
resolveTestUnit('''
fff() => 123;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'fff()',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -963,11 +1122,11 @@
''');
}
- void test_convertToBlockBody_OK_onValue() {
+ test_convertToBlockBody_OK_onValue() async {
resolveTestUnit('''
fff() => 123;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'23;',
DartAssistKind.CONVERT_INTO_BLOCK_BODY,
'''
@@ -977,23 +1136,53 @@
''');
}
- void test_convertToBlockBody_wrong_noEnclosingFunction() {
+ test_convertToExpressionBody_BAD_already() async {
resolveTestUnit('''
-var v = 123;
+fff() => 42;
''');
- assertNoAssistAt('v =', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+ await assertNoAssistAt(
+ 'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
}
- void test_convertToBlockBody_wrong_notExpressionBlock() {
+ test_convertToExpressionBody_BAD_moreThanOneStatement() async {
resolveTestUnit('''
fff() {
- return 123;
+ var v = 42;
+ return v;
}
''');
- assertNoAssistAt('fff() {', DartAssistKind.CONVERT_INTO_BLOCK_BODY);
+ await assertNoAssistAt(
+ 'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
}
- void test_convertToExpressionBody_OK_async() {
+ test_convertToExpressionBody_BAD_noEnclosingFunction() async {
+ resolveTestUnit('''
+var V = 42;
+''');
+ await assertNoAssistAt('V = ', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+ }
+
+ test_convertToExpressionBody_BAD_noReturn() async {
+ resolveTestUnit('''
+fff() {
+ var v = 42;
+}
+''');
+ await assertNoAssistAt(
+ 'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+ }
+
+ test_convertToExpressionBody_BAD_noReturnValue() async {
+ resolveTestUnit('''
+fff() {
+ return;
+}
+''');
+ await assertNoAssistAt(
+ 'fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
+ }
+
+ test_convertToExpressionBody_OK_async() async {
resolveTestUnit('''
class A {
mmm() async {
@@ -1001,7 +1190,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'mmm',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1011,7 +1200,7 @@
''');
}
- void test_convertToExpressionBody_OK_closure() {
+ test_convertToExpressionBody_OK_closure() async {
resolveTestUnit('''
setup(x) {}
main() {
@@ -1020,7 +1209,7 @@
});
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'42;',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1031,7 +1220,7 @@
''');
}
- void test_convertToExpressionBody_OK_closure_voidExpression() {
+ test_convertToExpressionBody_OK_closure_voidExpression() async {
resolveTestUnit('''
setup(x) {}
main() {
@@ -1040,7 +1229,7 @@
});
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'print(',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1051,7 +1240,7 @@
''');
}
- void test_convertToExpressionBody_OK_constructor() {
+ test_convertToExpressionBody_OK_constructor() async {
resolveTestUnit('''
class A {
factory A() {
@@ -1059,7 +1248,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'A()',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1069,13 +1258,13 @@
''');
}
- void test_convertToExpressionBody_OK_function_onBlock() {
+ test_convertToExpressionBody_OK_function_onBlock() async {
resolveTestUnit('''
fff() {
return 42;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'{',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1083,13 +1272,13 @@
''');
}
- void test_convertToExpressionBody_OK_function_onName() {
+ test_convertToExpressionBody_OK_function_onName() async {
resolveTestUnit('''
fff() {
return 42;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'ff()',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1097,7 +1286,7 @@
''');
}
- void test_convertToExpressionBody_OK_method_onBlock() {
+ test_convertToExpressionBody_OK_method_onBlock() async {
resolveTestUnit('''
class A {
m() { // marker
@@ -1105,7 +1294,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'{ // marker',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1115,13 +1304,13 @@
''');
}
- void test_convertToExpressionBody_OK_topFunction_onReturnStatement() {
+ test_convertToExpressionBody_OK_topFunction_onReturnStatement() async {
resolveTestUnit('''
fff() {
return 42;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'return',
DartAssistKind.CONVERT_INTO_EXPRESSION_BODY,
'''
@@ -1129,49 +1318,7 @@
''');
}
- void test_convertToExpressionBody_wrong_already() {
- resolveTestUnit('''
-fff() => 42;
-''');
- assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
- }
-
- void test_convertToExpressionBody_wrong_moreThanOneStatement() {
- resolveTestUnit('''
-fff() {
- var v = 42;
- return v;
-}
-''');
- assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
- }
-
- void test_convertToExpressionBody_wrong_noEnclosingFunction() {
- resolveTestUnit('''
-var V = 42;
-''');
- assertNoAssistAt('V = ', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
- }
-
- void test_convertToExpressionBody_wrong_noReturn() {
- resolveTestUnit('''
-fff() {
- var v = 42;
-}
-''');
- assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
- }
-
- void test_convertToExpressionBody_wrong_noReturnValue() {
- resolveTestUnit('''
-fff() {
- return;
-}
-''');
- assertNoAssistAt('fff()', DartAssistKind.CONVERT_INTO_EXPRESSION_BODY);
- }
-
- void test_convertToFieldParameter_BAD_additionalUse() {
+ test_convertToFieldParameter_BAD_additionalUse() async {
resolveTestUnit('''
class A {
int aaa2;
@@ -1179,20 +1326,20 @@
A(int aaa) : aaa2 = aaa, bbb2 = aaa;
}
''');
- assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+ await assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
}
- void test_convertToFieldParameter_BAD_notPureAssignment() {
+ test_convertToFieldParameter_BAD_notPureAssignment() async {
resolveTestUnit('''
class A {
int aaa2;
A(int aaa) : aaa2 = aaa * 2;
}
''');
- assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
+ await assertNoAssistAt('aaa)', DartAssistKind.CONVERT_TO_FIELD_PARAMETER);
}
- void test_convertToFieldParameter_OK_firstInitializer() {
+ test_convertToFieldParameter_OK_firstInitializer() async {
resolveTestUnit('''
class A {
double aaa2;
@@ -1200,7 +1347,7 @@
A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'aaa, ',
DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
'''
@@ -1212,7 +1359,7 @@
''');
}
- void test_convertToFieldParameter_OK_onParameterName_inInitializer() {
+ test_convertToFieldParameter_OK_onParameterName_inInitializer() async {
resolveTestUnit('''
class A {
int test2;
@@ -1220,7 +1367,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test {',
DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
'''
@@ -1232,7 +1379,7 @@
''');
}
- void test_convertToFieldParameter_OK_onParameterName_inParameters() {
+ test_convertToFieldParameter_OK_onParameterName_inParameters() async {
resolveTestUnit('''
class A {
int test;
@@ -1240,7 +1387,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test)',
DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
'''
@@ -1252,7 +1399,7 @@
''');
}
- void test_convertToFieldParameter_OK_secondInitializer() {
+ test_convertToFieldParameter_OK_secondInitializer() async {
resolveTestUnit('''
class A {
double aaa2;
@@ -1260,7 +1407,7 @@
A(int aaa, int bbb) : aaa2 = aaa, bbb2 = bbb;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'bbb)',
DartAssistKind.CONVERT_TO_FIELD_PARAMETER,
'''
@@ -1272,16 +1419,17 @@
''');
}
- void test_convertToForIndex_BAD_bodyNotBlock() {
+ test_convertToForIndex_BAD_bodyNotBlock() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) print(item);
}
''');
- assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+ await assertNoAssistAt(
+ 'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
}
- void test_convertToForIndex_BAD_doesNotDeclareVariable() {
+ test_convertToForIndex_BAD_doesNotDeclareVariable() async {
resolveTestUnit('''
main(List<String> items) {
String item;
@@ -1290,10 +1438,10 @@
}
}
''');
- assertNoAssistAt('for (item', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+ await assertNoAssistAt('for (item', DartAssistKind.CONVERT_INTO_FOR_INDEX);
}
- void test_convertToForIndex_BAD_iterableIsNotVariable() {
+ test_convertToForIndex_BAD_iterableIsNotVariable() async {
resolveTestUnit('''
main() {
for (String item in ['a', 'b', 'c']) {
@@ -1301,10 +1449,11 @@
}
}
''');
- assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+ await assertNoAssistAt(
+ 'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
}
- void test_convertToForIndex_BAD_iterableNotList() {
+ test_convertToForIndex_BAD_iterableNotList() async {
resolveTestUnit('''
main(Iterable<String> items) {
for (String item in items) {
@@ -1312,10 +1461,11 @@
}
}
''');
- assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+ await assertNoAssistAt(
+ 'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
}
- void test_convertToForIndex_BAD_usesIJK() {
+ test_convertToForIndex_BAD_usesIJK() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1324,10 +1474,11 @@
}
}
''');
- assertNoAssistAt('for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
+ await assertNoAssistAt(
+ 'for (String', DartAssistKind.CONVERT_INTO_FOR_INDEX);
}
- void test_convertToForIndex_OK_onDeclaredIdentifier_name() {
+ test_convertToForIndex_OK_onDeclaredIdentifier_name() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1335,7 +1486,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'item in',
DartAssistKind.CONVERT_INTO_FOR_INDEX,
'''
@@ -1348,7 +1499,7 @@
''');
}
- void test_convertToForIndex_OK_onDeclaredIdentifier_type() {
+ test_convertToForIndex_OK_onDeclaredIdentifier_type() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1356,7 +1507,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'tring item',
DartAssistKind.CONVERT_INTO_FOR_INDEX,
'''
@@ -1369,7 +1520,7 @@
''');
}
- void test_convertToForIndex_OK_onFor() {
+ test_convertToForIndex_OK_onFor() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1377,7 +1528,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'for (String',
DartAssistKind.CONVERT_INTO_FOR_INDEX,
'''
@@ -1390,7 +1541,7 @@
''');
}
- void test_convertToForIndex_OK_usesI() {
+ test_convertToForIndex_OK_usesI() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1398,7 +1549,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'for (String',
DartAssistKind.CONVERT_INTO_FOR_INDEX,
'''
@@ -1411,7 +1562,7 @@
''');
}
- void test_convertToForIndex_OK_usesIJ() {
+ test_convertToForIndex_OK_usesIJ() async {
resolveTestUnit('''
main(List<String> items) {
for (String item in items) {
@@ -1420,7 +1571,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'for (String',
DartAssistKind.CONVERT_INTO_FOR_INDEX,
'''
@@ -1434,13 +1585,96 @@
''');
}
- void test_convertToIsNot_OK_childOfIs_left() {
+ test_convertToIsNot_BAD_is_alreadyIsNot() async {
+ resolveTestUnit('''
+main(p) {
+ p is! String;
+}
+''');
+ await assertNoAssistAt('is!', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_is_noEnclosingParenthesis() async {
+ resolveTestUnit('''
+main(p) {
+ p is String;
+}
+''');
+ await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_is_noPrefix() async {
+ resolveTestUnit('''
+main(p) {
+ (p is String);
+}
+''');
+ await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_is_notIsExpression() async {
+ resolveTestUnit('''
+main(p) {
+ 123 + 456;
+}
+''');
+ await assertNoAssistAt('123 +', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_is_notTheNotOperator() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main(p) {
+ ++(p is String);
+}
+''');
+ await assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_not_alreadyIsNot() async {
+ resolveTestUnit('''
+main(p) {
+ !(p is! String);
+}
+''');
+ await assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_not_noEnclosingParenthesis() async {
+ resolveTestUnit('''
+main(p) {
+ !p;
+}
+''');
+ await assertNoAssistAt('!p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_not_notIsExpression() async {
+ resolveTestUnit('''
+main(p) {
+ !(p == null);
+}
+''');
+ await assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_BAD_not_notTheNotOperator() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main(p) {
+ ++(p is String);
+}
+''');
+ await assertNoAssistAt('++(', DartAssistKind.CONVERT_INTO_IS_NOT);
+ }
+
+ test_convertToIsNot_OK_childOfIs_left() async {
resolveTestUnit('''
main(p) {
!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'p is',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1450,13 +1684,13 @@
''');
}
- void test_convertToIsNot_OK_childOfIs_right() {
+ test_convertToIsNot_OK_childOfIs_right() async {
resolveTestUnit('''
main(p) {
!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'String)',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1466,13 +1700,13 @@
''');
}
- void test_convertToIsNot_OK_is() {
+ test_convertToIsNot_OK_is() async {
resolveTestUnit('''
main(p) {
!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'is String',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1482,13 +1716,13 @@
''');
}
- void test_convertToIsNot_OK_is_higherPrecedencePrefix() {
+ test_convertToIsNot_OK_is_higherPrecedencePrefix() async {
resolveTestUnit('''
main(p) {
!!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'is String',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1498,13 +1732,13 @@
''');
}
- void test_convertToIsNot_OK_is_not_higherPrecedencePrefix() {
+ test_convertToIsNot_OK_is_not_higherPrecedencePrefix() async {
resolveTestUnit('''
main(p) {
!!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'!(p',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1514,13 +1748,13 @@
''');
}
- void test_convertToIsNot_OK_not() {
+ test_convertToIsNot_OK_not() async {
resolveTestUnit('''
main(p) {
!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'!(p',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1530,13 +1764,13 @@
''');
}
- void test_convertToIsNot_OK_parentheses() {
+ test_convertToIsNot_OK_parentheses() async {
resolveTestUnit('''
main(p) {
!(p is String);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'(p is',
DartAssistKind.CONVERT_INTO_IS_NOT,
'''
@@ -1546,96 +1780,56 @@
''');
}
- void test_convertToIsNot_wrong_is_alreadyIsNot() {
- resolveTestUnit('''
-main(p) {
- p is! String;
-}
-''');
- assertNoAssistAt('is!', DartAssistKind.CONVERT_INTO_IS_NOT);
- }
-
- void test_convertToIsNot_wrong_is_noEnclosingParenthesis() {
- resolveTestUnit('''
-main(p) {
- p is String;
-}
-''');
- assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
- }
-
- void test_convertToIsNot_wrong_is_noPrefix() {
- resolveTestUnit('''
-main(p) {
- (p is String);
-}
-''');
- assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
- }
-
- void test_convertToIsNot_wrong_is_notIsExpression() {
- resolveTestUnit('''
-main(p) {
- 123 + 456;
-}
-''');
- assertNoAssistAt('123 +', DartAssistKind.CONVERT_INTO_IS_NOT);
- }
-
- void test_convertToIsNot_wrong_is_notTheNotOperator() {
+ test_convertToIsNotEmpty_BAD_noBang() async {
verifyNoTestUnitErrors = false;
resolveTestUnit('''
-main(p) {
- ++(p is String);
+main(String str) {
+ ~str.isEmpty;
}
''');
- assertNoAssistAt('is String', DartAssistKind.CONVERT_INTO_IS_NOT);
+ await assertNoAssistAt(
+ 'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
}
- void test_convertToIsNot_wrong_not_alreadyIsNot() {
+ test_convertToIsNotEmpty_BAD_noIsNotEmpty() async {
resolveTestUnit('''
-main(p) {
- !(p is! String);
+class A {
+ bool get isEmpty => false;
+}
+main(A a) {
+ !a.isEmpty;
}
''');
- assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ await assertNoAssistAt(
+ 'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
}
- void test_convertToIsNot_wrong_not_noEnclosingParenthesis() {
+ test_convertToIsNotEmpty_BAD_notInPrefixExpression() async {
resolveTestUnit('''
-main(p) {
- !p;
+main(String str) {
+ str.isEmpty;
}
''');
- assertNoAssistAt('!p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ await assertNoAssistAt(
+ 'isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
}
- void test_convertToIsNot_wrong_not_notIsExpression() {
+ test_convertToIsNotEmpty_BAD_notIsEmpty() async {
resolveTestUnit('''
-main(p) {
- !(p == null);
+main(int p) {
+ !p.isEven;
}
''');
- assertNoAssistAt('!(p', DartAssistKind.CONVERT_INTO_IS_NOT);
+ await assertNoAssistAt('isEven;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
}
- void test_convertToIsNot_wrong_not_notTheNotOperator() {
- verifyNoTestUnitErrors = false;
- resolveTestUnit('''
-main(p) {
- ++(p is String);
-}
-''');
- assertNoAssistAt('++(', DartAssistKind.CONVERT_INTO_IS_NOT);
- }
-
- void test_convertToIsNotEmpty_OK_on_isEmpty() {
+ test_convertToIsNotEmpty_OK_on_isEmpty() async {
resolveTestUnit('''
main(String str) {
!str.isEmpty;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'isEmpty',
DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
'''
@@ -1645,13 +1839,13 @@
''');
}
- void test_convertToIsNotEmpty_OK_on_str() {
+ test_convertToIsNotEmpty_OK_on_str() async {
resolveTestUnit('''
main(String str) {
!str.isEmpty;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'str.',
DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
'''
@@ -1661,13 +1855,13 @@
''');
}
- void test_convertToIsNotEmpty_OK_propertyAccess() {
+ test_convertToIsNotEmpty_OK_propertyAccess() async {
resolveTestUnit('''
main(String str) {
!'text'.isEmpty;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'isEmpty',
DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY,
'''
@@ -1677,47 +1871,7 @@
''');
}
- void test_convertToIsNotEmpty_wrong_noBang() {
- verifyNoTestUnitErrors = false;
- resolveTestUnit('''
-main(String str) {
- ~str.isEmpty;
-}
-''');
- assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
- }
-
- void test_convertToIsNotEmpty_wrong_noIsNotEmpty() {
- resolveTestUnit('''
-class A {
- bool get isEmpty => false;
-}
-main(A a) {
- !a.isEmpty;
-}
-''');
- assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
- }
-
- void test_convertToIsNotEmpty_wrong_notInPrefixExpression() {
- resolveTestUnit('''
-main(String str) {
- str.isEmpty;
-}
-''');
- assertNoAssistAt('isEmpty;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
- }
-
- void test_convertToIsNotEmpty_wrong_notIsEmpty() {
- resolveTestUnit('''
-main(int p) {
- !p.isEven;
-}
-''');
- assertNoAssistAt('isEven;', DartAssistKind.CONVERT_INTO_IS_NOT_EMPTY);
- }
-
- void test_convertToNormalParameter_OK_dynamic() {
+ test_convertToNormalParameter_OK_dynamic() async {
resolveTestUnit('''
class A {
var test;
@@ -1725,7 +1879,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test)',
DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
'''
@@ -1737,7 +1891,7 @@
''');
}
- void test_convertToNormalParameter_OK_firstInitializer() {
+ test_convertToNormalParameter_OK_firstInitializer() async {
resolveTestUnit('''
class A {
int test;
@@ -1745,7 +1899,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test)',
DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
'''
@@ -1757,7 +1911,7 @@
''');
}
- void test_convertToNormalParameter_OK_secondInitializer() {
+ test_convertToNormalParameter_OK_secondInitializer() async {
resolveTestUnit('''
class A {
double aaa;
@@ -1765,7 +1919,7 @@
A(this.bbb) : aaa = 1.0;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'bbb)',
DartAssistKind.CONVERT_TO_NORMAL_PARAMETER,
'''
@@ -1777,7 +1931,7 @@
''');
}
- void test_encapsulateField_BAD_alreadyPrivate() {
+ test_encapsulateField_BAD_alreadyPrivate() async {
resolveTestUnit('''
class A {
int _test = 42;
@@ -1786,19 +1940,19 @@
print(a._test);
}
''');
- assertNoAssistAt('_test =', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('_test =', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_BAD_final() {
+ test_encapsulateField_BAD_final() async {
resolveTestUnit('''
class A {
final int test = 42;
}
''');
- assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_BAD_multipleFields() {
+ test_encapsulateField_BAD_multipleFields() async {
resolveTestUnit('''
class A {
int aaa, bbb, ccc;
@@ -1807,19 +1961,19 @@
print(a.bbb);
}
''');
- assertNoAssistAt('bbb, ', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('bbb, ', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_BAD_notOnName() {
+ test_encapsulateField_BAD_notOnName() async {
resolveTestUnit('''
class A {
int test = 1 + 2 + 3;
}
''');
- assertNoAssistAt('+ 2', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('+ 2', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_BAD_parseError() {
+ test_encapsulateField_BAD_parseError() async {
verifyNoTestUnitErrors = false;
resolveTestUnit('''
class A {
@@ -1829,19 +1983,19 @@
print(a.test);
}
''');
- assertNoAssistAt('; // marker', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('; // marker', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_BAD_static() {
+ test_encapsulateField_BAD_static() async {
resolveTestUnit('''
class A {
static int test = 42;
}
''');
- assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
+ await assertNoAssistAt('test =', DartAssistKind.ENCAPSULATE_FIELD);
}
- void test_encapsulateField_OK_hasType() {
+ test_encapsulateField_OK_hasType() async {
resolveTestUnit('''
class A {
int test = 42;
@@ -1851,7 +2005,7 @@
print(a.test);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test = 42',
DartAssistKind.ENCAPSULATE_FIELD,
'''
@@ -1871,7 +2025,7 @@
''');
}
- void test_encapsulateField_OK_noType() {
+ test_encapsulateField_OK_noType() async {
resolveTestUnit('''
class A {
var test = 42;
@@ -1880,7 +2034,7 @@
print(a.test);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'test = 42',
DartAssistKind.ENCAPSULATE_FIELD,
'''
@@ -1899,20 +2053,48 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_compare() {
- Map<String, String> operatorMap = {
- '<': '>',
- '<=': '>=',
- '>': '<',
- '>=': '<='
- };
- operatorMap.forEach((initialOperator, resultOperator) {
+ test_exchangeBinaryExpressionArguments_BAD_extraLength() async {
+ resolveTestUnit('''
+main() {
+ 111 + 222;
+}
+''');
+ length = 3;
+ await assertNoAssistAt('+ 222', DartAssistKind.EXCHANGE_OPERANDS);
+ }
+
+ test_exchangeBinaryExpressionArguments_BAD_onOperand() async {
+ resolveTestUnit('''
+main() {
+ 111 + 222;
+}
+''');
+ length = 3;
+ await assertNoAssistAt('11 +', DartAssistKind.EXCHANGE_OPERANDS);
+ }
+
+ test_exchangeBinaryExpressionArguments_BAD_selectionWithBinary() async {
+ resolveTestUnit('''
+main() {
+ 1 + 2 + 3;
+}
+''');
+ length = '1 + 2 + 3'.length;
+ await assertNoAssistAt('1 + 2 + 3', DartAssistKind.EXCHANGE_OPERANDS);
+ }
+
+ test_exchangeBinaryExpressionArguments_OK_compare() async {
+ const initialOperators = const ['<', '<=', '>', '>='];
+ const resultOperators = const ['>', '>=', '<', '<='];
+ for (int i = 0; i <= 0; i++) {
+ String initialOperator = initialOperators[i];
+ String resultOperator = resultOperators[i];
resolveTestUnit('''
bool main(int a, int b) {
return a $initialOperator b;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
initialOperator,
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -1920,16 +2102,16 @@
return b $resultOperator a;
}
''');
- });
+ }
}
- void test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_1() {
+ test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_1() async {
resolveTestUnit('''
main() {
1 * 2 * 3 + 4;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'* 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -1939,13 +2121,13 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_2() {
+ test_exchangeBinaryExpressionArguments_OK_extended_mixOperator_2() async {
resolveTestUnit('''
main() {
1 + 2 - 3 + 4;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'+ 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -1955,13 +2137,13 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterFirst() {
+ test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterFirst() async {
resolveTestUnit('''
main() {
1 + 2 + 3;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'+ 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -1971,13 +2153,13 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterSecond() {
+ test_exchangeBinaryExpressionArguments_OK_extended_sameOperator_afterSecond() async {
resolveTestUnit('''
main() {
1 + 2 + 3;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'+ 3',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -1987,13 +2169,13 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_simple_afterOperator() {
+ test_exchangeBinaryExpressionArguments_OK_simple_afterOperator() async {
resolveTestUnit('''
main() {
1 + 2;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
' 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -2003,13 +2185,13 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_simple_beforeOperator() {
+ test_exchangeBinaryExpressionArguments_OK_simple_beforeOperator() async {
resolveTestUnit('''
main() {
1 + 2;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'+ 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -2019,14 +2201,14 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_simple_fullSelection() {
+ test_exchangeBinaryExpressionArguments_OK_simple_fullSelection() async {
resolveTestUnit('''
main() {
1 + 2;
}
''');
length = '1 + 2'.length;
- assertHasAssistAt(
+ await assertHasAssistAt(
'1 + 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -2036,14 +2218,14 @@
''');
}
- void test_exchangeBinaryExpressionArguments_OK_simple_withLength() {
+ test_exchangeBinaryExpressionArguments_OK_simple_withLength() async {
resolveTestUnit('''
main() {
1 + 2;
}
''');
length = 2;
- assertHasAssistAt(
+ await assertHasAssistAt(
'+ 2',
DartAssistKind.EXCHANGE_OPERANDS,
'''
@@ -2053,61 +2235,31 @@
''');
}
- void test_exchangeBinaryExpressionArguments_wrong_extraLength() {
- resolveTestUnit('''
-main() {
- 111 + 222;
-}
-''');
- length = 3;
- assertNoAssistAt('+ 222', DartAssistKind.EXCHANGE_OPERANDS);
- }
-
- void test_exchangeBinaryExpressionArguments_wrong_onOperand() {
- resolveTestUnit('''
-main() {
- 111 + 222;
-}
-''');
- length = 3;
- assertNoAssistAt('11 +', DartAssistKind.EXCHANGE_OPERANDS);
- }
-
- void test_exchangeBinaryExpressionArguments_wrong_selectionWithBinary() {
- resolveTestUnit('''
-main() {
- 1 + 2 + 3;
-}
-''');
- length = '1 + 2 + 3'.length;
- assertNoAssistAt('1 + 2 + 3', DartAssistKind.EXCHANGE_OPERANDS);
- }
-
- void test_importAddShow_BAD_hasShow() {
+ test_importAddShow_BAD_hasShow() async {
resolveTestUnit('''
import 'dart:math' show PI;
main() {
PI;
}
''');
- assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+ await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
}
- void test_importAddShow_BAD_unresolvedUri() {
+ test_importAddShow_BAD_unresolvedUri() async {
resolveTestUnit('''
import '/no/such/lib.dart';
''');
- assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+ await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
}
- void test_importAddShow_BAD_unused() {
+ test_importAddShow_BAD_unused() async {
resolveTestUnit('''
import 'dart:math';
''');
- assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
+ await assertNoAssistAt('import ', DartAssistKind.IMPORT_ADD_SHOW);
}
- void test_importAddShow_OK_hasUnresolvedIdentifier() {
+ test_importAddShow_OK_hasUnresolvedIdentifier() async {
resolveTestUnit('''
import 'dart:math';
main(x) {
@@ -2115,7 +2267,7 @@
return x.foo();
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'import ',
DartAssistKind.IMPORT_ADD_SHOW,
'''
@@ -2127,7 +2279,7 @@
''');
}
- void test_importAddShow_OK_onDirective() {
+ test_importAddShow_OK_onDirective() async {
resolveTestUnit('''
import 'dart:math';
main() {
@@ -2136,7 +2288,7 @@
max(1, 2);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'import ',
DartAssistKind.IMPORT_ADD_SHOW,
'''
@@ -2149,7 +2301,7 @@
''');
}
- void test_importAddShow_OK_onUri() {
+ test_importAddShow_OK_onUri() async {
resolveTestUnit('''
import 'dart:math';
main() {
@@ -2158,7 +2310,7 @@
max(1, 2);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'art:math',
DartAssistKind.IMPORT_ADD_SHOW,
'''
@@ -2171,27 +2323,27 @@
''');
}
- void test_introduceLocalTestedType_BAD_notBlock() {
+ test_introduceLocalTestedType_BAD_notBlock() async {
resolveTestUnit('''
main(p) {
if (p is String)
print('not a block');
}
''');
- assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+ await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
}
- void test_introduceLocalTestedType_BAD_notIsExpression() {
+ test_introduceLocalTestedType_BAD_notIsExpression() async {
resolveTestUnit('''
main(p) {
if (p == null) {
}
}
''');
- assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
+ await assertNoAssistAt('if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE);
}
- void test_introduceLocalTestedType_OK_if_is() {
+ test_introduceLocalTestedType_OK_if_is() async {
resolveTestUnit('''
class MyTypeName {}
main(p) {
@@ -2209,7 +2361,7 @@
p = null;
}
''';
- assertHasAssistAt(
+ await assertHasAssistAt(
'is MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
_assertLinkedGroup(
change.linkedEditGroups[0],
@@ -2217,11 +2369,11 @@
expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
['myTypeName', 'typeName', 'name']));
// another good location
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
}
- void test_introduceLocalTestedType_OK_if_isNot() {
+ test_introduceLocalTestedType_OK_if_isNot() async {
resolveTestUnit('''
class MyTypeName {}
main(p) {
@@ -2239,7 +2391,7 @@
MyTypeName myTypeName = p;
}
''';
- assertHasAssistAt(
+ await assertHasAssistAt(
'is! MyType', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
_assertLinkedGroup(
change.linkedEditGroups[0],
@@ -2247,11 +2399,11 @@
expectedSuggestions(LinkedEditSuggestionKind.VARIABLE,
['myTypeName', 'typeName', 'name']));
// another good location
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
}
- void test_introduceLocalTestedType_OK_while() {
+ test_introduceLocalTestedType_OK_while() async {
resolveTestUnit('''
main(p) {
while (p is String) {
@@ -2267,20 +2419,20 @@
p = null;
}
''';
- assertHasAssistAt(
+ await assertHasAssistAt(
'is String', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
- assertHasAssistAt(
+ await assertHasAssistAt(
'while (p', DartAssistKind.INTRODUCE_LOCAL_CAST_TYPE, expected);
}
- void test_invalidSelection() {
+ test_invalidSelection() async {
resolveTestUnit('');
List<Assist> assists =
- computeAssists(plugin, context, testUnit.element.source, -1, 0);
+ await computeAssists(plugin, context, testUnit.element.source, -1, 0);
expect(assists, isEmpty);
}
- void test_invertIfStatement_blocks() {
+ test_invertIfStatement_blocks() async {
resolveTestUnit('''
main() {
if (true) {
@@ -2290,7 +2442,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (',
DartAssistKind.INVERT_IF_STATEMENT,
'''
@@ -2304,7 +2456,7 @@
''');
}
- void test_invertIfStatement_statements() {
+ test_invertIfStatement_statements() async {
resolveTestUnit('''
main() {
if (true)
@@ -2313,7 +2465,7 @@
1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (',
DartAssistKind.INVERT_IF_STATEMENT,
'''
@@ -2326,7 +2478,85 @@
''');
}
- void test_joinIfStatementInner_OK_conditionAndOr() {
+ test_joinIfStatementInner_BAD_innerNotIf() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ print(0);
+ }
+}
+''');
+ await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_BAD_innerWithElse() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ if (2 == 2) {
+ print(0);
+ } else {
+ print(1);
+ }
+ }
+}
+''');
+ await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_BAD_statementAfterInner() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ if (2 == 2) {
+ print(2);
+ }
+ print(1);
+ }
+}
+''');
+ await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_BAD_statementBeforeInner() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ print(1);
+ if (2 == 2) {
+ print(2);
+ }
+ }
+}
+''');
+ await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_BAD_targetNotIf() async {
+ resolveTestUnit('''
+main() {
+ print(0);
+}
+''');
+ await assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_BAD_targetWithElse() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ if (2 == 2) {
+ print(0);
+ }
+ } else {
+ print(1);
+ }
+}
+''');
+ await assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ }
+
+ test_joinIfStatementInner_OK_conditionAndOr() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2336,7 +2566,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2348,7 +2578,7 @@
''');
}
- void test_joinIfStatementInner_OK_conditionInvocation() {
+ test_joinIfStatementInner_OK_conditionInvocation() async {
resolveTestUnit('''
main() {
if (isCheck()) {
@@ -2359,7 +2589,7 @@
}
bool isCheck() => false;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (isCheck',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2372,7 +2602,7 @@
''');
}
- void test_joinIfStatementInner_OK_conditionOrAnd() {
+ test_joinIfStatementInner_OK_conditionOrAnd() async {
resolveTestUnit('''
main() {
if (1 == 1 || 2 == 2) {
@@ -2382,7 +2612,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2394,7 +2624,7 @@
''');
}
- void test_joinIfStatementInner_OK_onCondition() {
+ test_joinIfStatementInner_OK_onCondition() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2404,7 +2634,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2416,7 +2646,7 @@
''');
}
- void test_joinIfStatementInner_OK_simpleConditions_block_block() {
+ test_joinIfStatementInner_OK_simpleConditions_block_block() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2426,7 +2656,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2438,7 +2668,7 @@
''');
}
- void test_joinIfStatementInner_OK_simpleConditions_block_single() {
+ test_joinIfStatementInner_OK_simpleConditions_block_single() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2447,7 +2677,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2459,7 +2689,7 @@
''');
}
- void test_joinIfStatementInner_OK_simpleConditions_single_blockMulti() {
+ test_joinIfStatementInner_OK_simpleConditions_single_blockMulti() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2471,7 +2701,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2485,7 +2715,7 @@
''');
}
- void test_joinIfStatementInner_OK_simpleConditions_single_blockOne() {
+ test_joinIfStatementInner_OK_simpleConditions_single_blockOne() async {
resolveTestUnit('''
main() {
if (1 == 1)
@@ -2494,7 +2724,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (1 ==',
DartAssistKind.JOIN_IF_WITH_INNER,
'''
@@ -2506,7 +2736,7 @@
''');
}
- void test_joinIfStatementInner_wrong_innerNotIf() {
+ test_joinIfStatementOuter_BAD_outerNotIf() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2514,34 +2744,10 @@
}
}
''');
- assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ await assertNoAssistAt('if (1 == 1', DartAssistKind.JOIN_IF_WITH_OUTER);
}
- void test_joinIfStatementInner_wrong_innerWithElse() {
- resolveTestUnit('''
-main() {
- if (1 == 1) {
- if (2 == 2) {
- print(0);
- } else {
- print(1);
- }
- }
-}
-''');
- assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
- }
-
- void test_joinIfStatementInner_wrong_targetNotIf() {
- resolveTestUnit('''
-main() {
- print(0);
-}
-''');
- assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_INNER);
- }
-
- void test_joinIfStatementInner_wrong_targetWithElse() {
+ test_joinIfStatementOuter_BAD_outerWithElse() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2553,10 +2759,62 @@
}
}
''');
- assertNoAssistAt('if (1 ==', DartAssistKind.JOIN_IF_WITH_INNER);
+ await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
}
- void test_joinIfStatementOuter_OK_conditionAndOr() {
+ test_joinIfStatementOuter_BAD_statementAfterInner() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ if (2 == 2) {
+ print(2);
+ }
+ print(1);
+ }
+}
+''');
+ await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+ }
+
+ test_joinIfStatementOuter_BAD_statementBeforeInner() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ print(1);
+ if (2 == 2) {
+ print(2);
+ }
+ }
+}
+''');
+ await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+ }
+
+ test_joinIfStatementOuter_BAD_targetNotIf() async {
+ resolveTestUnit('''
+main() {
+ print(0);
+}
+''');
+ await assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_OUTER);
+ }
+
+ test_joinIfStatementOuter_BAD_targetWithElse() async {
+ resolveTestUnit('''
+main() {
+ if (1 == 1) {
+ if (2 == 2) {
+ print(0);
+ } else {
+ print(1);
+ }
+ }
+}
+''');
+ await assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
+ }
+
+ test_joinIfStatementOuter_OK_conditionAndOr() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2566,7 +2824,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 ==',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2578,7 +2836,7 @@
''');
}
- void test_joinIfStatementOuter_OK_conditionInvocation() {
+ test_joinIfStatementOuter_OK_conditionInvocation() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2589,7 +2847,7 @@
}
bool isCheck() => false;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (isCheck',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2602,7 +2860,7 @@
''');
}
- void test_joinIfStatementOuter_OK_conditionOrAnd() {
+ test_joinIfStatementOuter_OK_conditionOrAnd() async {
resolveTestUnit('''
main() {
if (1 == 1 || 2 == 2) {
@@ -2612,7 +2870,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (3 == 3',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2624,7 +2882,7 @@
''');
}
- void test_joinIfStatementOuter_OK_onCondition() {
+ test_joinIfStatementOuter_OK_onCondition() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2634,7 +2892,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 == 2',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2646,7 +2904,7 @@
''');
}
- void test_joinIfStatementOuter_OK_simpleConditions_block_block() {
+ test_joinIfStatementOuter_OK_simpleConditions_block_block() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2656,7 +2914,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 == 2',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2668,7 +2926,7 @@
''');
}
- void test_joinIfStatementOuter_OK_simpleConditions_block_single() {
+ test_joinIfStatementOuter_OK_simpleConditions_block_single() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2677,7 +2935,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 == 2',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2689,7 +2947,7 @@
''');
}
- void test_joinIfStatementOuter_OK_simpleConditions_single_blockMulti() {
+ test_joinIfStatementOuter_OK_simpleConditions_single_blockMulti() async {
resolveTestUnit('''
main() {
if (1 == 1) {
@@ -2701,7 +2959,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 == 2',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2715,7 +2973,7 @@
''');
}
- void test_joinIfStatementOuter_OK_simpleConditions_single_blockOne() {
+ test_joinIfStatementOuter_OK_simpleConditions_single_blockOne() async {
resolveTestUnit('''
main() {
if (1 == 1)
@@ -2724,7 +2982,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (2 == 2',
DartAssistKind.JOIN_IF_WITH_OUTER,
'''
@@ -2736,64 +2994,98 @@
''');
}
- void test_joinIfStatementOuter_wrong_outerNotIf() {
+ test_joinVariableDeclaration_onAssignment_BAD_hasInitializer() async {
resolveTestUnit('''
main() {
- if (1 == 1) {
- print(0);
+ var v = 1;
+ v = 2;
+}
+''');
+ await assertNoAssistAt('v = 2', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notAdjacent() async {
+ resolveTestUnit('''
+main() {
+ var v;
+ var bar;
+ v = 1;
+}
+''');
+ await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notAssignment() async {
+ resolveTestUnit('''
+main() {
+ var v;
+ v += 1;
+}
+''');
+ await assertNoAssistAt('v += 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notDeclaration() async {
+ resolveTestUnit('''
+main(var v) {
+ v = 1;
+}
+''');
+ await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notLeftArgument() async {
+ resolveTestUnit('''
+main() {
+ var v;
+ 1 + v; // marker
+}
+''');
+ await assertNoAssistAt(
+ 'v; // marker', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notOneVariable() async {
+ resolveTestUnit('''
+main() {
+ var v, v2;
+ v = 1;
+}
+''');
+ await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notResolved() async {
+ verifyNoTestUnitErrors = false;
+ resolveTestUnit('''
+main() {
+ var v;
+ x = 1;
+}
+''');
+ await assertNoAssistAt('x = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onAssignment_BAD_notSameBlock() async {
+ resolveTestUnit('''
+main() {
+ var v;
+ {
+ v = 1;
}
}
''');
- assertNoAssistAt('if (1 == 1', DartAssistKind.JOIN_IF_WITH_OUTER);
+ await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
}
- void test_joinIfStatementOuter_wrong_outerWithElse() {
- resolveTestUnit('''
-main() {
- if (1 == 1) {
- if (2 == 2) {
- print(0);
- }
- } else {
- print(1);
- }
-}
-''');
- assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
- }
-
- void test_joinIfStatementOuter_wrong_targetNotIf() {
- resolveTestUnit('''
-main() {
- print(0);
-}
-''');
- assertNoAssistAt('print', DartAssistKind.JOIN_IF_WITH_OUTER);
- }
-
- void test_joinIfStatementOuter_wrong_targetWithElse() {
- resolveTestUnit('''
-main() {
- if (1 == 1) {
- if (2 == 2) {
- print(0);
- } else {
- print(1);
- }
- }
-}
-''');
- assertNoAssistAt('if (2 == 2', DartAssistKind.JOIN_IF_WITH_OUTER);
- }
-
- void test_joinVariableDeclaration_onAssignment_OK() {
+ test_joinVariableDeclaration_onAssignment_OK() async {
resolveTestUnit('''
main() {
var v;
v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.JOIN_VARIABLE_DECLARATION,
'''
@@ -2803,97 +3095,74 @@
''');
}
- void test_joinVariableDeclaration_onAssignment_wrong_hasInitializer() {
+ test_joinVariableDeclaration_onDeclaration_BAD_hasInitializer() async {
resolveTestUnit('''
main() {
var v = 1;
v = 2;
}
''');
- assertNoAssistAt('v = 2', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ await assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
}
- void test_joinVariableDeclaration_onAssignment_wrong_notAdjacent() {
+ test_joinVariableDeclaration_onDeclaration_BAD_lastStatement() async {
+ resolveTestUnit('''
+main() {
+ if (true)
+ var v;
+}
+''');
+ await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onDeclaration_BAD_nextNotAssignmentExpression() async {
resolveTestUnit('''
main() {
var v;
- var bar;
- v = 1;
+ 42;
}
''');
- assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
}
- void test_joinVariableDeclaration_onAssignment_wrong_notAssignment() {
+ test_joinVariableDeclaration_onDeclaration_BAD_nextNotExpressionStatement() async {
+ resolveTestUnit('''
+main() {
+ var v;
+ if (true) return;
+}
+''');
+ await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ }
+
+ test_joinVariableDeclaration_onDeclaration_BAD_nextNotPureAssignment() async {
resolveTestUnit('''
main() {
var v;
v += 1;
}
''');
- assertNoAssistAt('v += 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ await assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
}
- void test_joinVariableDeclaration_onAssignment_wrong_notDeclaration() {
- resolveTestUnit('''
-main(var v) {
- v = 1;
-}
-''');
- assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onAssignment_wrong_notLeftArgument() {
- resolveTestUnit('''
-main() {
- var v;
- 1 + v; // marker
-}
-''');
- assertNoAssistAt('v; // marker', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onAssignment_wrong_notOneVariable() {
+ test_joinVariableDeclaration_onDeclaration_BAD_notOneVariable() async {
resolveTestUnit('''
main() {
var v, v2;
v = 1;
}
''');
- assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
+ await assertNoAssistAt('v, ', DartAssistKind.JOIN_VARIABLE_DECLARATION);
}
- void test_joinVariableDeclaration_onAssignment_wrong_notResolved() {
- verifyNoTestUnitErrors = false;
- resolveTestUnit('''
-main() {
- var v;
- x = 1;
-}
-''');
- assertNoAssistAt('x = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onAssignment_wrong_notSameBlock() {
- resolveTestUnit('''
-main() {
- var v;
- {
- v = 1;
- }
-}
-''');
- assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_OK_onName() {
+ test_joinVariableDeclaration_onDeclaration_OK_onName() async {
resolveTestUnit('''
main() {
var v;
v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v;',
DartAssistKind.JOIN_VARIABLE_DECLARATION,
'''
@@ -2903,14 +3172,14 @@
''');
}
- void test_joinVariableDeclaration_onDeclaration_OK_onType() {
+ test_joinVariableDeclaration_onDeclaration_OK_onType() async {
resolveTestUnit('''
main() {
int v;
v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int v',
DartAssistKind.JOIN_VARIABLE_DECLARATION,
'''
@@ -2920,14 +3189,14 @@
''');
}
- void test_joinVariableDeclaration_onDeclaration_OK_onVar() {
+ test_joinVariableDeclaration_onDeclaration_OK_onVar() async {
resolveTestUnit('''
main() {
var v;
v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'var v',
DartAssistKind.JOIN_VARIABLE_DECLARATION,
'''
@@ -2937,73 +3206,13 @@
''');
}
- void test_joinVariableDeclaration_onDeclaration_wrong_hasInitializer() {
- resolveTestUnit('''
-main() {
- var v = 1;
- v = 2;
-}
-''');
- assertNoAssistAt('v = 1', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_wrong_lastStatement() {
- resolveTestUnit('''
-main() {
- if (true)
- var v;
-}
-''');
- assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_wrong_nextNotAssignmentExpression() {
- resolveTestUnit('''
-main() {
- var v;
- 42;
-}
-''');
- assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_wrong_nextNotExpressionStatement() {
- resolveTestUnit('''
-main() {
- var v;
- if (true) return;
-}
-''');
- assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_wrong_nextNotPureAssignment() {
- resolveTestUnit('''
-main() {
- var v;
- v += 1;
-}
-''');
- assertNoAssistAt('v;', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_joinVariableDeclaration_onDeclaration_wrong_notOneVariable() {
- resolveTestUnit('''
-main() {
- var v, v2;
- v = 1;
-}
-''');
- assertNoAssistAt('v, ', DartAssistKind.JOIN_VARIABLE_DECLARATION);
- }
-
- void test_removeTypeAnnotation_classField_OK() {
+ test_removeTypeAnnotation_classField_OK() async {
resolveTestUnit('''
class A {
int v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v = ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3013,13 +3222,13 @@
''');
}
- void test_removeTypeAnnotation_classField_OK_final() {
+ test_removeTypeAnnotation_classField_OK_final() async {
resolveTestUnit('''
class A {
final int v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v = ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3029,13 +3238,13 @@
''');
}
- void test_removeTypeAnnotation_localVariable_OK() {
+ test_removeTypeAnnotation_localVariable_OK() async {
resolveTestUnit('''
main() {
int a = 1, b = 2;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3045,13 +3254,13 @@
''');
}
- void test_removeTypeAnnotation_localVariable_OK_const() {
+ test_removeTypeAnnotation_localVariable_OK_const() async {
resolveTestUnit('''
main() {
const int v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3061,13 +3270,13 @@
''');
}
- void test_removeTypeAnnotation_localVariable_OK_final() {
+ test_removeTypeAnnotation_localVariable_OK_final() async {
resolveTestUnit('''
main() {
final int v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3077,11 +3286,11 @@
''');
}
- void test_removeTypeAnnotation_topLevelVariable_OK() {
+ test_removeTypeAnnotation_topLevelVariable_OK() async {
resolveTestUnit('''
int V = 1;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3089,11 +3298,11 @@
''');
}
- void test_removeTypeAnnotation_topLevelVariable_OK_final() {
+ test_removeTypeAnnotation_topLevelVariable_OK_final() async {
resolveTestUnit('''
final int V = 1;
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.REMOVE_TYPE_ANNOTATION,
'''
@@ -3101,7 +3310,25 @@
''');
}
- void test_replaceConditionalWithIfElse_OK_assignment() {
+ test_replaceConditionalWithIfElse_BAD_noEnclosingStatement() async {
+ resolveTestUnit('''
+var v = true ? 111 : 222;
+''');
+ await assertNoAssistAt(
+ '? 111', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+ }
+
+ test_replaceConditionalWithIfElse_BAD_notConditional() async {
+ resolveTestUnit('''
+main() {
+ var v = 42;
+}
+''');
+ await assertNoAssistAt(
+ 'v = 42', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+ }
+
+ test_replaceConditionalWithIfElse_OK_assignment() async {
resolveTestUnit('''
main() {
var v;
@@ -3109,7 +3336,7 @@
}
''');
// on conditional
- assertHasAssistAt(
+ await assertHasAssistAt(
'11 :',
DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
@@ -3123,7 +3350,7 @@
}
''');
// on variable
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
@@ -3138,13 +3365,13 @@
''');
}
- void test_replaceConditionalWithIfElse_OK_return() {
+ test_replaceConditionalWithIfElse_OK_return() async {
resolveTestUnit('''
main() {
return true ? 111 : 222;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'return ',
DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
@@ -3158,13 +3385,13 @@
''');
}
- void test_replaceConditionalWithIfElse_OK_variableDeclaration() {
+ test_replaceConditionalWithIfElse_OK_variableDeclaration() async {
resolveTestUnit('''
main() {
int a = 1, vvv = true ? 111 : 222, b = 2;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'11 :',
DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE,
'''
@@ -3179,23 +3406,48 @@
''');
}
- void test_replaceConditionalWithIfElse_wrong_noEnclosingStatement() {
- resolveTestUnit('''
-var v = true ? 111 : 222;
-''');
- assertNoAssistAt('? 111', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
- }
-
- void test_replaceConditionalWithIfElse_wrong_notConditional() {
+ test_replaceIfElseWithConditional_BAD_expressionVsReturn() async {
resolveTestUnit('''
main() {
- var v = 42;
+ if (true) {
+ print(42);
+ } else {
+ return;
+ }
}
''');
- assertNoAssistAt('v = 42', DartAssistKind.REPLACE_CONDITIONAL_WITH_IF_ELSE);
+ await assertNoAssistAt(
+ 'else', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
}
- void test_replaceIfElseWithConditional_OK_assignment() {
+ test_replaceIfElseWithConditional_BAD_notIfStatement() async {
+ resolveTestUnit('''
+main() {
+ print(0);
+}
+''');
+ await assertNoAssistAt(
+ 'print', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+ }
+
+ test_replaceIfElseWithConditional_BAD_notSingleStatement() async {
+ resolveTestUnit('''
+main() {
+ int vvv;
+ if (true) {
+ print(0);
+ vvv = 111;
+ } else {
+ print(0);
+ vvv = 222;
+ }
+}
+''');
+ await assertNoAssistAt(
+ 'if (true)', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+ }
+
+ test_replaceIfElseWithConditional_OK_assignment() async {
resolveTestUnit('''
main() {
int vvv;
@@ -3206,7 +3458,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (true)',
DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
'''
@@ -3217,7 +3469,7 @@
''');
}
- void test_replaceIfElseWithConditional_OK_return() {
+ test_replaceIfElseWithConditional_OK_return() async {
resolveTestUnit('''
main() {
if (true) {
@@ -3227,7 +3479,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'if (true)',
DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL,
'''
@@ -3237,46 +3489,55 @@
''');
}
- void test_replaceIfElseWithConditional_wrong_expressionVsReturn() {
+ test_splitAndCondition_BAD_hasElse() async {
resolveTestUnit('''
main() {
- if (true) {
- print(42);
+ if (1 == 1 && 2 == 2) {
+ print(1);
} else {
- return;
+ print(2);
}
}
''');
- assertNoAssistAt('else', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+ await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
}
- void test_replaceIfElseWithConditional_wrong_notIfStatement() {
+ test_splitAndCondition_BAD_notAnd() async {
resolveTestUnit('''
main() {
- print(0);
+ if (1 == 1 || 2 == 2) {
+ print(0);
+ }
}
''');
- assertNoAssistAt('print', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+ await assertNoAssistAt('|| 2', DartAssistKind.SPLIT_AND_CONDITION);
}
- void test_replaceIfElseWithConditional_wrong_notSingleStatememt() {
+ test_splitAndCondition_BAD_notPartOfIf() async {
resolveTestUnit('''
main() {
- int vvv;
- if (true) {
+ print(1 == 1 && 2 == 2);
+}
+''');
+ await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+ }
+
+ test_splitAndCondition_BAD_notTopLevelAnd() async {
+ resolveTestUnit('''
+main() {
+ if (true || (1 == 1 && 2 == 2)) {
print(0);
- vvv = 111;
- } else {
+ }
+ if (true && (3 == 3 && 4 == 4)) {
print(0);
- vvv = 222;
}
}
''');
- assertNoAssistAt(
- 'if (true)', DartAssistKind.REPLACE_IF_ELSE_WITH_CONDITIONAL);
+ await assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+ await assertNoAssistAt('&& 4', DartAssistKind.SPLIT_AND_CONDITION);
}
- void test_splitAndCondition_OK_innerAndExpression() {
+ test_splitAndCondition_OK_innerAndExpression() async {
resolveTestUnit('''
main() {
if (1 == 1 && 2 == 2 && 3 == 3) {
@@ -3284,7 +3545,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'&& 2 == 2',
DartAssistKind.SPLIT_AND_CONDITION,
'''
@@ -3298,7 +3559,7 @@
''');
}
- void test_splitAndCondition_OK_thenBlock() {
+ test_splitAndCondition_OK_thenBlock() async {
resolveTestUnit('''
main() {
if (true && false) {
@@ -3309,7 +3570,7 @@
}
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'&& false',
DartAssistKind.SPLIT_AND_CONDITION,
'''
@@ -3326,14 +3587,14 @@
''');
}
- void test_splitAndCondition_OK_thenStatement() {
+ test_splitAndCondition_OK_thenStatement() async {
resolveTestUnit('''
main() {
if (true && false)
print(0);
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'&& false',
DartAssistKind.SPLIT_AND_CONDITION,
'''
@@ -3345,7 +3606,7 @@
''');
}
- void test_splitAndCondition_wrong() {
+ test_splitAndCondition_wrong() async {
resolveTestUnit('''
main() {
if (1 == 1 && 2 == 2) {
@@ -3355,69 +3616,30 @@
}
''');
// not binary expression
- assertNoAssistAt('main() {', DartAssistKind.SPLIT_AND_CONDITION);
+ await assertNoAssistAt('main() {', DartAssistKind.SPLIT_AND_CONDITION);
// selection is not empty and includes more than just operator
{
length = 5;
- assertNoAssistAt('&& 2 == 2', DartAssistKind.SPLIT_AND_CONDITION);
+ await assertNoAssistAt('&& 2 == 2', DartAssistKind.SPLIT_AND_CONDITION);
}
}
- void test_splitAndCondition_wrong_hasElse() {
+ test_splitVariableDeclaration_BAD_notOneVariable() async {
resolveTestUnit('''
main() {
- if (1 == 1 && 2 == 2) {
- print(1);
- } else {
- print(2);
- }
+ var v = 1, v2;
}
''');
- assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
+ await assertNoAssistAt('v = 1', DartAssistKind.SPLIT_VARIABLE_DECLARATION);
}
- void test_splitAndCondition_wrong_notAnd() {
- resolveTestUnit('''
-main() {
- if (1 == 1 || 2 == 2) {
- print(0);
- }
-}
-''');
- assertNoAssistAt('|| 2', DartAssistKind.SPLIT_AND_CONDITION);
- }
-
- void test_splitAndCondition_wrong_notPartOfIf() {
- resolveTestUnit('''
-main() {
- print(1 == 1 && 2 == 2);
-}
-''');
- assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
- }
-
- void test_splitAndCondition_wrong_notTopLevelAnd() {
- resolveTestUnit('''
-main() {
- if (true || (1 == 1 && 2 == 2)) {
- print(0);
- }
- if (true && (3 == 3 && 4 == 4)) {
- print(0);
- }
-}
-''');
- assertNoAssistAt('&& 2', DartAssistKind.SPLIT_AND_CONDITION);
- assertNoAssistAt('&& 4', DartAssistKind.SPLIT_AND_CONDITION);
- }
-
- void test_splitVariableDeclaration_OK_onName() {
+ test_splitVariableDeclaration_OK_onName() async {
resolveTestUnit('''
main() {
var v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'v =',
DartAssistKind.SPLIT_VARIABLE_DECLARATION,
'''
@@ -3428,13 +3650,13 @@
''');
}
- void test_splitVariableDeclaration_OK_onType() {
+ test_splitVariableDeclaration_OK_onType() async {
resolveTestUnit('''
main() {
int v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'int ',
DartAssistKind.SPLIT_VARIABLE_DECLARATION,
'''
@@ -3445,13 +3667,13 @@
''');
}
- void test_splitVariableDeclaration_OK_onVar() {
+ test_splitVariableDeclaration_OK_onVar() async {
resolveTestUnit('''
main() {
var v = 1;
}
''');
- assertHasAssistAt(
+ await assertHasAssistAt(
'var ',
DartAssistKind.SPLIT_VARIABLE_DECLARATION,
'''
@@ -3462,16 +3684,7 @@
''');
}
- void test_splitVariableDeclaration_wrong_notOneVariable() {
- resolveTestUnit('''
-main() {
- var v = 1, v2;
-}
-''');
- assertNoAssistAt('v = 1', DartAssistKind.SPLIT_VARIABLE_DECLARATION);
- }
-
- void test_surroundWith_block() {
+ test_surroundWith_block() async {
resolveTestUnit('''
main() {
// start
@@ -3481,7 +3694,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_BLOCK,
'''
main() {
@@ -3495,7 +3708,7 @@
''');
}
- void test_surroundWith_doWhile() {
+ test_surroundWith_doWhile() async {
resolveTestUnit('''
main() {
// start
@@ -3505,7 +3718,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_DO_WHILE,
'''
main() {
@@ -3519,7 +3732,7 @@
''');
}
- void test_surroundWith_for() {
+ test_surroundWith_for() async {
resolveTestUnit('''
main() {
// start
@@ -3529,7 +3742,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_FOR,
'''
main() {
@@ -3543,7 +3756,7 @@
''');
}
- void test_surroundWith_forIn() {
+ test_surroundWith_forIn() async {
resolveTestUnit('''
main() {
// start
@@ -3553,7 +3766,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_FOR_IN,
'''
main() {
@@ -3567,7 +3780,7 @@
''');
}
- void test_surroundWith_if() {
+ test_surroundWith_if() async {
resolveTestUnit('''
main() {
// start
@@ -3577,7 +3790,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_IF,
'''
main() {
@@ -3591,7 +3804,7 @@
''');
}
- void test_surroundWith_tryCatch() {
+ test_surroundWith_tryCatch() async {
resolveTestUnit('''
main() {
// start
@@ -3601,7 +3814,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_TRY_CATCH,
'''
main() {
@@ -3617,7 +3830,7 @@
''');
}
- void test_surroundWith_tryFinally() {
+ test_surroundWith_tryFinally() async {
resolveTestUnit('''
main() {
// start
@@ -3627,7 +3840,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_TRY_FINALLY,
'''
main() {
@@ -3643,7 +3856,7 @@
''');
}
- void test_surroundWith_while() {
+ test_surroundWith_while() async {
resolveTestUnit('''
main() {
// start
@@ -3653,7 +3866,7 @@
}
''');
_setStartEndSelection();
- assertHasAssist(
+ await assertHasAssist(
DartAssistKind.SURROUND_WITH_WHILE,
'''
main() {
@@ -3670,8 +3883,8 @@
/**
* Computes assists and verifies that there is an assist of the given kind.
*/
- Assist _assertHasAssist(AssistKind kind) {
- List<Assist> assists = computeAssists(
+ Future<Assist> _assertHasAssist(AssistKind kind) async {
+ List<Assist> assists = await computeAssists(
plugin, context, testUnit.element.source, offset, length);
for (Assist assist in assists) {
if (assist.kind == kind) {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 5d124f0..a6ec27a 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -4,7 +4,10 @@
library test.services.correction.fix;
+import 'dart:async';
+
import 'package:analysis_server/plugin/edit/fix/fix_core.dart';
+import 'package:analysis_server/plugin/edit/fix/fix_dart.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart'
hide AnalysisError;
import 'package:analysis_server/src/services/correction/fix.dart';
@@ -42,14 +45,14 @@
SourceChange change;
String resultCode;
- void assert_undefinedFunction_create_returnType_bool(String lineWithTest) {
+ assert_undefinedFunction_create_returnType_bool(String lineWithTest) async {
resolveTestUnit('''
main() {
bool b = true;
$lineWithTest
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -62,9 +65,9 @@
''');
}
- void assertHasFix(FixKind kind, String expected) {
+ assertHasFix(FixKind kind, String expected) async {
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(kind, error);
+ fix = await _assertHasFix(kind, error);
change = fix.change;
// apply to "file"
List<SourceFileEdit> fileEdits = change.edits;
@@ -74,9 +77,9 @@
expect(resultCode, expected);
}
- void assertNoFix(FixKind kind) {
+ assertNoFix(FixKind kind) async {
AnalysisError error = _findErrorToFix();
- List<Fix> fixes = _computeFixes(error);
+ List<Fix> fixes = await _computeFixes(error);
for (Fix fix in fixes) {
if (fix.kind == kind) {
throw fail('Unexpected fix $kind in\n${fixes.join('\n')}');
@@ -109,7 +112,7 @@
verifyNoTestUnitErrors = false;
}
- void test_addFieldFormalParameters_hasRequiredParameter() {
+ test_addFieldFormalParameters_hasRequiredParameter() async {
resolveTestUnit('''
class Test {
final int a;
@@ -118,7 +121,7 @@
Test(this.a);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
'''
class Test {
@@ -130,7 +133,7 @@
''');
}
- void test_addFieldFormalParameters_noParameters() {
+ test_addFieldFormalParameters_noParameters() async {
resolveTestUnit('''
class Test {
final int a;
@@ -139,7 +142,7 @@
Test();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
'''
class Test {
@@ -151,7 +154,7 @@
''');
}
- void test_addFieldFormalParameters_noRequiredParameter() {
+ test_addFieldFormalParameters_noRequiredParameter() async {
resolveTestUnit('''
class Test {
final int a;
@@ -160,7 +163,7 @@
Test([this.c]);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_FIELD_FORMAL_PARAMETERS,
'''
class Test {
@@ -172,14 +175,24 @@
''');
}
- void test_addMissingParameter_function_positional_hasZero() {
+ test_addMissingParameter_function_positional_hasNamed() async {
+ resolveTestUnit('''
+test({int a}) {}
+main() {
+ test(1);
+}
+''');
+ await assertNoFix(DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL);
+ }
+
+ test_addMissingParameter_function_positional_hasZero() async {
resolveTestUnit('''
test() {}
main() {
test(1);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
'''
test([int i]) {}
@@ -189,14 +202,31 @@
''');
}
- void test_addMissingParameter_function_required_hasOne() {
+ test_addMissingParameter_function_required_hasNamed() async {
+ resolveTestUnit('''
+test({int a}) {}
+main() {
+ test(1);
+}
+''');
+ await assertHasFix(
+ DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
+ '''
+test(int i, {int a}) {}
+main() {
+ test(1);
+}
+''');
+ }
+
+ test_addMissingParameter_function_required_hasOne() async {
resolveTestUnit('''
test(int a) {}
main() {
test(1, 2.0);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
'''
test(int a, double d) {}
@@ -206,14 +236,14 @@
''');
}
- void test_addMissingParameter_function_required_hasZero() {
+ test_addMissingParameter_function_required_hasZero() async {
resolveTestUnit('''
test() {}
main() {
test(1);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
'''
test(int i) {}
@@ -223,7 +253,7 @@
''');
}
- void test_addMissingParameter_method_positional_hasOne() {
+ test_addMissingParameter_method_positional_hasOne() async {
resolveTestUnit('''
class A {
test(int a) {}
@@ -232,7 +262,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_POSITIONAL,
'''
class A {
@@ -244,7 +274,7 @@
''');
}
- void test_addMissingParameter_method_required_hasOne() {
+ test_addMissingParameter_method_required_hasOne() async {
resolveTestUnit('''
class A {
test(int a) {}
@@ -253,7 +283,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
'''
class A {
@@ -265,7 +295,7 @@
''');
}
- void test_addMissingParameter_method_required_hasZero() {
+ test_addMissingParameter_method_required_hasZero() async {
resolveTestUnit('''
class A {
test() {}
@@ -274,7 +304,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_MISSING_PARAMETER_REQUIRED,
'''
class A {
@@ -286,7 +316,7 @@
''');
}
- void test_addPartOfDirective() {
+ test_addPartOfDirective() async {
String partCode = r'''
// Comment first.
// Comment second.
@@ -300,7 +330,7 @@
''');
_performAnalysis();
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.ADD_PART_OF, error);
+ fix = await _assertHasFix(DartFixKind.ADD_PART_OF, error);
change = fix.change;
// apply to "file"
List<SourceFileEdit> fileEdits = change.edits;
@@ -319,14 +349,14 @@
''');
}
- void test_addSync_BAD_nullFunctionBody() {
+ test_addSync_BAD_nullFunctionBody() async {
resolveTestUnit('''
var F = await;
''');
- assertNoFix(DartFixKind.ADD_ASYNC);
+ await assertNoFix(DartFixKind.ADD_ASYNC);
}
- void test_addSync_blockFunctionBody() {
+ test_addSync_blockFunctionBody() async {
resolveTestUnit('''
foo() {}
main() {
@@ -340,11 +370,11 @@
expect(errors.map((e) => e.message), unorderedEquals([message1, message2]));
for (AnalysisError error in errors) {
if (error.message == message1) {
- List<Fix> fixes = _computeFixes(error);
+ List<Fix> fixes = await _computeFixes(error);
expect(fixes, isEmpty);
}
if (error.message == message2) {
- List<Fix> fixes = _computeFixes(error);
+ List<Fix> fixes = await _computeFixes(error);
// has exactly one fix
expect(fixes, hasLength(1));
Fix fix = fixes[0];
@@ -366,7 +396,7 @@
}
}
- void test_addSync_expressionFunctionBody() {
+ test_addSync_expressionFunctionBody() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
};
@@ -374,7 +404,7 @@
foo() {}
main() => await foo();
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_ASYNC,
'''
foo() {}
@@ -382,13 +412,13 @@
''');
}
- void test_boolean() {
+ test_boolean() async {
resolveTestUnit('''
main() {
boolean v;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_BOOLEAN_WITH_BOOL,
'''
main() {
@@ -397,13 +427,13 @@
''');
}
- void test_canBeNullAfterNullAware_chain() {
+ test_canBeNullAfterNullAware_chain() async {
resolveTestUnit('''
main(x) {
x?.a.b.c;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_WITH_NULL_AWARE,
'''
main(x) {
@@ -412,13 +442,13 @@
''');
}
- void test_canBeNullAfterNullAware_methodInvocation() {
+ test_canBeNullAfterNullAware_methodInvocation() async {
resolveTestUnit('''
main(x) {
x?.a.b();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_WITH_NULL_AWARE,
'''
main(x) {
@@ -427,13 +457,13 @@
''');
}
- void test_canBeNullAfterNullAware_propertyAccess() {
+ test_canBeNullAfterNullAware_propertyAccess() async {
resolveTestUnit('''
main(x) {
x?.a().b;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_WITH_NULL_AWARE,
'''
main(x) {
@@ -442,7 +472,7 @@
''');
}
- void test_changeToStaticAccess_method() {
+ test_changeToStaticAccess_method() async {
resolveTestUnit('''
class A {
static foo() {}
@@ -451,7 +481,7 @@
a.foo();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
class A {
@@ -463,7 +493,7 @@
''');
}
- void test_changeToStaticAccess_method_importType() {
+ test_changeToStaticAccess_method_importType() async {
addSource(
'/libA.dart',
r'''
@@ -485,7 +515,7 @@
b.foo();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
import 'libB.dart';
@@ -496,14 +526,14 @@
''');
}
- void test_changeToStaticAccess_method_prefixLibrary() {
+ test_changeToStaticAccess_method_prefixLibrary() async {
resolveTestUnit('''
import 'dart:async' as pref;
main(pref.Future f) {
f.wait([]);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
import 'dart:async' as pref;
@@ -513,7 +543,7 @@
''');
}
- void test_changeToStaticAccess_property() {
+ test_changeToStaticAccess_property() async {
resolveTestUnit('''
class A {
static get foo => 42;
@@ -522,7 +552,7 @@
a.foo;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
class A {
@@ -534,7 +564,7 @@
''');
}
- void test_changeToStaticAccess_property_importType() {
+ test_changeToStaticAccess_property_importType() async {
addSource(
'/libA.dart',
r'''
@@ -556,7 +586,7 @@
b.foo;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
import 'libB.dart';
@@ -567,13 +597,62 @@
''');
}
- void test_createClass() {
+ 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() {
Test v = null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CLASS,
'''
main() {
@@ -586,16 +665,16 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
}
- void test_createClass_BAD_hasUnresolvedPrefix() {
+ test_createClass_BAD_hasUnresolvedPrefix() async {
resolveTestUnit('''
main() {
prefix.Test v = null;
}
''');
- assertNoFix(DartFixKind.CREATE_CLASS);
+ await assertNoFix(DartFixKind.CREATE_CLASS);
}
- void test_createClass_inLibraryOfPrefix() {
+ test_createClass_inLibraryOfPrefix() async {
String libCode = r'''
library my.lib;
@@ -611,7 +690,7 @@
}
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_CLASS, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_CLASS, error);
change = fix.change;
// apply to "lib.dart"
List<SourceFileEdit> fileEdits = change.edits;
@@ -631,7 +710,7 @@
expect(change.linkedEditGroups, isEmpty);
}
- void test_createClass_innerLocalFunction() {
+ test_createClass_innerLocalFunction() async {
resolveTestUnit('''
f() {
g() {
@@ -639,7 +718,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CLASS,
'''
f() {
@@ -654,13 +733,13 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['Test v =', 'Test {']);
}
- void test_createClass_itemOfList() {
+ test_createClass_itemOfList() async {
resolveTestUnit('''
main() {
var a = [Test];
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CLASS,
'''
main() {
@@ -673,7 +752,7 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['Test];', 'Test {']);
}
- void test_createClass_itemOfList_inAnnotation() {
+ test_createClass_itemOfList_inAnnotation() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
};
@@ -684,7 +763,7 @@
@MyAnnotation(int, const [Test])
main() {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CLASS,
'''
class MyAnnotation {
@@ -699,7 +778,7 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['Test])', 'Test {']);
}
- void test_createConstructor_forFinalFields() {
+ test_createConstructor_forFinalFields() async {
errorFilter = (AnalysisError error) {
return error.message.contains("'a'");
};
@@ -710,7 +789,7 @@
final int c;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS,
'''
class Test {
@@ -723,7 +802,7 @@
''');
}
- void test_createConstructor_insteadOfSyntheticDefault() {
+ test_createConstructor_insteadOfSyntheticDefault() async {
resolveTestUnit('''
class A {
int field;
@@ -734,7 +813,7 @@
new A(1, 2.0);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR,
'''
class A {
@@ -751,7 +830,7 @@
''');
}
- void test_createConstructor_named() {
+ test_createConstructor_named() async {
resolveTestUnit('''
class A {
method() {}
@@ -760,7 +839,7 @@
new A.named(1, 2.0);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR,
'''
class A {
@@ -776,23 +855,23 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['named(int ', 'named(1']);
}
- void test_createConstructorForFinalFields_inTopLevelMethod() {
+ test_createConstructorForFinalFields_inTopLevelMethod() async {
resolveTestUnit('''
main() {
final int v;
}
''');
- assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+ await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
}
- void test_createConstructorForFinalFields_topLevelField() {
+ test_createConstructorForFinalFields_topLevelField() async {
resolveTestUnit('''
final int v;
''');
- assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
+ await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_FOR_FINAL_FIELDS);
}
- void test_createConstructorSuperExplicit() {
+ test_createConstructorSuperExplicit() async {
resolveTestUnit('''
class A {
A(bool p1, int p2, double p3, String p4, {p5});
@@ -801,7 +880,7 @@
B() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
'''
class A {
@@ -813,7 +892,7 @@
''');
}
- void test_createConstructorSuperExplicit_hasInitializers() {
+ test_createConstructorSuperExplicit_hasInitializers() async {
resolveTestUnit('''
class A {
A(int p);
@@ -823,7 +902,7 @@
B() : field = 42 {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
'''
class A {
@@ -836,7 +915,7 @@
''');
}
- void test_createConstructorSuperExplicit_named() {
+ test_createConstructorSuperExplicit_named() async {
resolveTestUnit('''
class A {
A.named(int p);
@@ -845,7 +924,7 @@
B() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
'''
class A {
@@ -857,7 +936,7 @@
''');
}
- void test_createConstructorSuperExplicit_named_private() {
+ test_createConstructorSuperExplicit_named_private() async {
resolveTestUnit('''
class A {
A._named(int p);
@@ -866,10 +945,10 @@
B() {}
}
''');
- assertNoFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
+ await assertNoFix(DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION);
}
- void test_createConstructorSuperExplicit_typeArgument() {
+ test_createConstructorSuperExplicit_typeArgument() async {
resolveTestUnit('''
class A<T> {
A(T p);
@@ -878,7 +957,7 @@
B();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_SUPER_CONSTRUCTOR_INVOCATION,
'''
class A<T> {
@@ -890,7 +969,7 @@
''');
}
- void test_createConstructorSuperImplicit() {
+ test_createConstructorSuperImplicit() async {
resolveTestUnit('''
class A {
A(p1, int p2, List<String> p3, [int p4]);
@@ -901,7 +980,7 @@
void existingMethod() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
class A {
@@ -917,7 +996,7 @@
''');
}
- void test_createConstructorSuperImplicit_fieldInitializer() {
+ test_createConstructorSuperImplicit_fieldInitializer() async {
resolveTestUnit('''
class A {
int _field;
@@ -929,7 +1008,7 @@
void existingMethod() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
class A {
@@ -946,7 +1025,7 @@
''');
}
- void test_createConstructorSuperImplicit_importType() {
+ test_createConstructorSuperImplicit_importType() async {
addSource(
'/libA.dart',
r'''
@@ -967,7 +1046,7 @@
class C extends B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
import 'libB.dart';
@@ -978,7 +1057,7 @@
''');
}
- void test_createConstructorSuperImplicit_named() {
+ test_createConstructorSuperImplicit_named() async {
resolveTestUnit('''
class A {
A.named(p1, int p2);
@@ -989,7 +1068,7 @@
void existingMethod() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
class A {
@@ -1005,7 +1084,7 @@
''');
}
- void test_createConstructorSuperImplicit_private() {
+ test_createConstructorSuperImplicit_private() async {
resolveTestUnit('''
class A {
A._named(p);
@@ -1013,10 +1092,10 @@
class B extends A {
}
''');
- assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER);
+ await assertNoFix(DartFixKind.CREATE_CONSTRUCTOR_SUPER);
}
- void test_createConstructorSuperImplicit_typeArgument() {
+ test_createConstructorSuperImplicit_typeArgument() async {
resolveTestUnit('''
class C<T> {
final T x;
@@ -1024,7 +1103,7 @@
}
class D extends C<int> {
}''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
class C<T> {
@@ -1036,7 +1115,7 @@
}''');
}
- void test_createField_BAD_inEnum() {
+ test_createField_BAD_inEnum() async {
resolveTestUnit('''
enum MyEnum {
AAA, BBB
@@ -1045,19 +1124,19 @@
MyEnum.foo;
}
''');
- assertNoFix(DartFixKind.CREATE_FIELD);
+ await assertNoFix(DartFixKind.CREATE_FIELD);
}
- void test_createField_BAD_inSDK() {
+ test_createField_BAD_inSDK() async {
resolveTestUnit('''
main(List p) {
p.foo = 1;
}
''');
- assertNoFix(DartFixKind.CREATE_FIELD);
+ await assertNoFix(DartFixKind.CREATE_FIELD);
}
- void test_createField_getter_multiLevel() {
+ test_createField_getter_multiLevel() async {
resolveTestUnit('''
class A {
}
@@ -1071,7 +1150,7 @@
int v = c.b.a.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1089,7 +1168,7 @@
''');
}
- void test_createField_getter_qualified_instance() {
+ test_createField_getter_qualified_instance() async {
resolveTestUnit('''
class A {
}
@@ -1097,7 +1176,7 @@
int v = a.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1109,7 +1188,7 @@
''');
}
- void test_createField_getter_qualified_instance_dynamicType() {
+ test_createField_getter_qualified_instance_dynamicType() async {
resolveTestUnit('''
class A {
B b;
@@ -1120,7 +1199,7 @@
class B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1135,7 +1214,7 @@
''');
}
- void test_createField_getter_unqualified_instance_asInvocationArgument() {
+ test_createField_getter_unqualified_instance_asInvocationArgument() async {
resolveTestUnit('''
class A {
main() {
@@ -1144,7 +1223,7 @@
}
f(String s) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1158,7 +1237,7 @@
''');
}
- void test_createField_getter_unqualified_instance_assignmentRhs() {
+ test_createField_getter_unqualified_instance_assignmentRhs() async {
resolveTestUnit('''
class A {
main() {
@@ -1166,7 +1245,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1179,7 +1258,7 @@
''');
}
- void test_createField_getter_unqualified_instance_asStatement() {
+ test_createField_getter_unqualified_instance_asStatement() async {
resolveTestUnit('''
class A {
main() {
@@ -1187,7 +1266,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1200,7 +1279,7 @@
''');
}
- void test_createField_hint() {
+ test_createField_hint() async {
resolveTestUnit('''
class A {
}
@@ -1209,7 +1288,7 @@
int v = x.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1222,7 +1301,7 @@
''');
}
- void test_createField_hint_setter() {
+ test_createField_hint_setter() async {
resolveTestUnit('''
class A {
}
@@ -1231,7 +1310,7 @@
x.test = 0;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1244,7 +1323,7 @@
''');
}
- void test_createField_importType() {
+ test_createField_importType() async {
addSource(
'/libA.dart',
r'''
@@ -1266,7 +1345,7 @@
c.test = getA();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
import 'libB.dart';
@@ -1280,7 +1359,7 @@
''');
}
- void test_createField_setter_generic_BAD() {
+ test_createField_setter_generic_BAD() async {
resolveTestUnit('''
class A {
}
@@ -1291,7 +1370,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1306,7 +1385,7 @@
''');
}
- void test_createField_setter_generic_OK_local() {
+ test_createField_setter_generic_OK_local() async {
resolveTestUnit('''
class A<T> {
List<T> items;
@@ -1316,7 +1395,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A<T> {
@@ -1331,7 +1410,7 @@
''');
}
- void test_createField_setter_qualified_instance_hasField() {
+ test_createField_setter_qualified_instance_hasField() async {
resolveTestUnit('''
class A {
int aaa;
@@ -1343,7 +1422,7 @@
a.test = 5;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1360,7 +1439,7 @@
''');
}
- void test_createField_setter_qualified_instance_hasMethod() {
+ test_createField_setter_qualified_instance_hasMethod() async {
resolveTestUnit('''
class A {
existingMethod() {}
@@ -1369,7 +1448,7 @@
a.test = 5;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1383,7 +1462,7 @@
''');
}
- void test_createField_setter_qualified_static() {
+ test_createField_setter_qualified_static() async {
resolveTestUnit('''
class A {
}
@@ -1391,7 +1470,7 @@
A.test = 5;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1403,7 +1482,7 @@
''');
}
- void test_createField_setter_unqualified_instance() {
+ test_createField_setter_unqualified_instance() async {
resolveTestUnit('''
class A {
main() {
@@ -1411,7 +1490,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1424,7 +1503,7 @@
''');
}
- void test_createField_setter_unqualified_static() {
+ test_createField_setter_unqualified_static() async {
resolveTestUnit('''
class A {
static main() {
@@ -1432,7 +1511,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
class A {
@@ -1445,13 +1524,13 @@
''');
}
- void test_createFile_forImport() {
+ test_createFile_forImport() async {
testFile = '/my/project/bin/test.dart';
resolveTestUnit('''
import 'my_file.dart';
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
change = fix.change;
// validate change
List<SourceFileEdit> fileEdits = change.edits;
@@ -1463,7 +1542,24 @@
expect(fileEdit.edits[0].replacement, contains('library my_file;'));
}
- void test_createFile_forImport_inPackage_lib() {
+ test_createFile_forImport_BAD_inPackage_lib_justLib() async {
+ provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
+ testFile = '/projects/my_package/test.dart';
+ resolveTestUnit('''
+import 'lib';
+''');
+ await assertNoFix(DartFixKind.CREATE_FILE);
+ }
+
+ test_createFile_forImport_BAD_notDart() async {
+ testFile = '/my/project/bin/test.dart';
+ resolveTestUnit('''
+import 'my_file.txt';
+''');
+ await assertNoFix(DartFixKind.CREATE_FILE);
+ }
+
+ test_createFile_forImport_inPackage_lib() async {
provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
testFile = '/projects/my_package/lib/test.dart';
provider.newFolder('/projects/my_package/lib');
@@ -1471,7 +1567,7 @@
import 'a/bb/c_cc/my_lib.dart';
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
change = fix.change;
// validate change
List<SourceFileEdit> fileEdits = change.edits;
@@ -1484,14 +1580,14 @@
contains('library my_package.a.bb.c_cc.my_lib;'));
}
- void test_createFile_forImport_inPackage_test() {
+ test_createFile_forImport_inPackage_test() async {
provider.newFile('/projects/my_package/pubspec.yaml', 'name: my_package');
testFile = '/projects/my_package/test/misc/test_all.dart';
resolveTestUnit('''
import 'a/bb/my_lib.dart';
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
change = fix.change;
// validate change
List<SourceFileEdit> fileEdits = change.edits;
@@ -1504,14 +1600,14 @@
contains('library my_package.test.misc.a.bb.my_lib;'));
}
- void test_createFile_forPart() {
+ test_createFile_forPart() async {
testFile = '/my/project/bin/test.dart';
resolveTestUnit('''
library my.lib;
part 'my_part.dart';
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
change = fix.change;
// validate change
List<SourceFileEdit> fileEdits = change.edits;
@@ -1523,7 +1619,7 @@
expect(fileEdit.edits[0].replacement, contains('part of my.lib;'));
}
- void test_createFile_forPart_inPackageLib() {
+ test_createFile_forPart_inPackageLib() async {
provider.newFile(
'/my/pubspec.yaml',
r'''
@@ -1545,7 +1641,7 @@
// prepare fix
testUnit = resolveLibraryUnit(testSource);
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_FILE, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_FILE, error);
change = fix.change;
// validate change
List<SourceFileEdit> fileEdits = change.edits;
@@ -1557,16 +1653,16 @@
expect(fileEdit.edits[0].replacement, contains('part of my.lib;'));
}
- void test_createGetter_BAD_inSDK() {
+ test_createGetter_BAD_inSDK() async {
resolveTestUnit('''
main(List p) {
int v = p.foo;
}
''');
- assertNoFix(DartFixKind.CREATE_GETTER);
+ await assertNoFix(DartFixKind.CREATE_GETTER);
}
- void test_createGetter_hint_getter() {
+ test_createGetter_hint_getter() async {
resolveTestUnit('''
class A {
}
@@ -1575,7 +1671,7 @@
int v = x.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1588,7 +1684,7 @@
''');
}
- void test_createGetter_location_afterLastGetter() {
+ test_createGetter_location_afterLastGetter() async {
resolveTestUnit('''
class A {
int existingField;
@@ -1601,7 +1697,7 @@
int v = a.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1619,7 +1715,7 @@
''');
}
- void test_createGetter_multiLevel() {
+ test_createGetter_multiLevel() async {
resolveTestUnit('''
class A {
}
@@ -1633,7 +1729,7 @@
int v = c.b.a.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1651,7 +1747,7 @@
''');
}
- void test_createGetter_qualified_instance() {
+ test_createGetter_qualified_instance() async {
resolveTestUnit('''
class A {
}
@@ -1659,7 +1755,7 @@
int v = a.test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1671,7 +1767,7 @@
''');
}
- void test_createGetter_qualified_instance_dynamicType() {
+ test_createGetter_qualified_instance_dynamicType() async {
resolveTestUnit('''
class A {
B b;
@@ -1682,7 +1778,7 @@
class B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1697,7 +1793,7 @@
''');
}
- void test_createGetter_setterContext() {
+ test_createGetter_setterContext() async {
resolveTestUnit('''
class A {
}
@@ -1705,10 +1801,10 @@
a.test = 42;
}
''');
- assertNoFix(DartFixKind.CREATE_GETTER);
+ await assertNoFix(DartFixKind.CREATE_GETTER);
}
- void test_createGetter_unqualified_instance_asInvocationArgument() {
+ test_createGetter_unqualified_instance_asInvocationArgument() async {
resolveTestUnit('''
class A {
main() {
@@ -1717,7 +1813,7 @@
}
f(String s) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1731,7 +1827,7 @@
''');
}
- void test_createGetter_unqualified_instance_assignmentLhs() {
+ test_createGetter_unqualified_instance_assignmentLhs() async {
resolveTestUnit('''
class A {
main() {
@@ -1739,10 +1835,10 @@
}
}
''');
- assertNoFix(DartFixKind.CREATE_GETTER);
+ await assertNoFix(DartFixKind.CREATE_GETTER);
}
- void test_createGetter_unqualified_instance_assignmentRhs() {
+ test_createGetter_unqualified_instance_assignmentRhs() async {
resolveTestUnit('''
class A {
main() {
@@ -1750,7 +1846,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1763,7 +1859,7 @@
''');
}
- void test_createGetter_unqualified_instance_asStatement() {
+ test_createGetter_unqualified_instance_asStatement() async {
resolveTestUnit('''
class A {
main() {
@@ -1771,7 +1867,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_GETTER,
'''
class A {
@@ -1784,7 +1880,7 @@
''');
}
- void test_createLocalVariable_functionType_named() {
+ test_createLocalVariable_functionType_named() async {
resolveTestUnit('''
typedef MY_FUNCTION(int p);
foo(MY_FUNCTION f) {}
@@ -1792,7 +1888,7 @@
foo(bar);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
typedef MY_FUNCTION(int p);
@@ -1804,23 +1900,23 @@
''');
}
- void test_createLocalVariable_functionType_synthetic() {
+ test_createLocalVariable_functionType_synthetic() async {
resolveTestUnit('''
foo(f(int p)) {}
main() {
foo(bar);
}
''');
- assertNoFix(DartFixKind.CREATE_LOCAL_VARIABLE);
+ await assertNoFix(DartFixKind.CREATE_LOCAL_VARIABLE);
}
- void test_createLocalVariable_read_typeAssignment() {
+ test_createLocalVariable_read_typeAssignment() async {
resolveTestUnit('''
main() {
int a = test;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1830,7 +1926,7 @@
''');
}
- void test_createLocalVariable_read_typeCondition() {
+ test_createLocalVariable_read_typeCondition() async {
resolveTestUnit('''
main() {
if (!test) {
@@ -1838,7 +1934,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1850,14 +1946,14 @@
''');
}
- void test_createLocalVariable_read_typeInvocationArgument() {
+ test_createLocalVariable_read_typeInvocationArgument() async {
resolveTestUnit('''
main() {
f(test);
}
f(String p) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1870,13 +1966,13 @@
_assertLinkedGroup(change.linkedEditGroups[1], ['test;', 'test);']);
}
- void test_createLocalVariable_read_typeInvocationTarget() {
+ test_createLocalVariable_read_typeInvocationTarget() async {
resolveTestUnit('''
main() {
test.add('hello');
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1887,13 +1983,13 @@
_assertLinkedGroup(change.linkedEditGroups[0], ['test;', 'test.add(']);
}
- void test_createLocalVariable_write_assignment() {
+ test_createLocalVariable_write_assignment() async {
resolveTestUnit('''
main() {
test = 42;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1902,13 +1998,13 @@
''');
}
- void test_createLocalVariable_write_assignment_compound() {
+ test_createLocalVariable_write_assignment_compound() async {
resolveTestUnit('''
main() {
test += 42;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_LOCAL_VARIABLE,
'''
main() {
@@ -1918,7 +2014,7 @@
''');
}
- void test_createMissingOverrides_functionTypeAlias() {
+ test_createMissingOverrides_functionTypeAlias() async {
resolveTestUnit('''
typedef int Binary(int left, int right);
@@ -1929,7 +2025,7 @@
class MyEmulator extends Emulator {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
typedef int Binary(int left, int right);
@@ -1947,7 +2043,7 @@
''');
}
- void test_createMissingOverrides_functionTypedParameter() {
+ test_createMissingOverrides_functionTypedParameter() async {
resolveTestUnit('''
abstract class A {
forEach(int f(double p1, String p2));
@@ -1956,7 +2052,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class A {
@@ -1972,7 +2068,7 @@
''');
}
- void test_createMissingOverrides_generics_typeArguments() {
+ test_createMissingOverrides_generics_typeArguments() async {
resolveTestUnit('''
class Iterator<T> {
}
@@ -1984,7 +2080,7 @@
class Test extends IterableMixin<int> {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
class Iterator<T> {
@@ -2002,7 +2098,7 @@
''');
}
- void test_createMissingOverrides_generics_typeParameters() {
+ test_createMissingOverrides_generics_typeParameters() async {
resolveTestUnit('''
abstract class ItemProvider<T> {
List<T> getItems();
@@ -2011,7 +2107,7 @@
class Test<V> extends ItemProvider<V> {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class ItemProvider<T> {
@@ -2027,7 +2123,7 @@
''');
}
- void test_createMissingOverrides_getter() {
+ test_createMissingOverrides_getter() async {
resolveTestUnit('''
abstract class A {
get g1;
@@ -2037,7 +2133,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class A {
@@ -2057,7 +2153,7 @@
''');
}
- void test_createMissingOverrides_importPrefix() {
+ test_createMissingOverrides_importPrefix() async {
resolveTestUnit('''
import 'dart:async' as aaa;
abstract class A {
@@ -2067,7 +2163,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
import 'dart:async' as aaa;
@@ -2084,7 +2180,7 @@
''');
}
- void test_createMissingOverrides_mergeToField_getterSetter() {
+ test_createMissingOverrides_mergeToField_getterSetter() async {
resolveTestUnit('''
class A {
int ma;
@@ -2095,7 +2191,7 @@
class B implements A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
class A {
@@ -2117,7 +2213,7 @@
''');
}
- void test_createMissingOverrides_method() {
+ test_createMissingOverrides_method() async {
resolveTestUnit('''
abstract class A {
m1();
@@ -2173,7 +2269,7 @@
}
}
''';
- assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, expectedCode);
+ await assertHasFix(DartFixKind.CREATE_MISSING_OVERRIDES, expectedCode);
// end position should be on "m1", not on "m2", "m3", etc
{
Position endPosition = change.selection;
@@ -2190,7 +2286,7 @@
}
}
- void test_createMissingOverrides_operator() {
+ test_createMissingOverrides_operator() async {
resolveTestUnit('''
abstract class A {
int operator [](int index);
@@ -2200,7 +2296,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class A {
@@ -2222,7 +2318,7 @@
''');
}
- void test_createMissingOverrides_setter() {
+ test_createMissingOverrides_setter() async {
resolveTestUnit('''
abstract class A {
set s1(x);
@@ -2233,7 +2329,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_MISSING_OVERRIDES,
'''
abstract class A {
@@ -2261,7 +2357,7 @@
''');
}
- void test_createNoSuchMethod() {
+ test_createNoSuchMethod() async {
resolveTestUnit('''
abstract class A {
m1();
@@ -2272,7 +2368,7 @@
existing() {}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_NO_SUCH_METHOD,
'''
abstract class A {
@@ -2288,7 +2384,7 @@
''');
}
- void test_creationFunction_forFunctionType_cascadeSecond() {
+ test_creationFunction_forFunctionType_cascadeSecond() async {
resolveTestUnit('''
class A {
B ma() => null;
@@ -2302,7 +2398,7 @@
a..ma().useFunction(test);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
class A {
@@ -2322,14 +2418,14 @@
''');
}
- void test_creationFunction_forFunctionType_coreFunction() {
+ test_creationFunction_forFunctionType_coreFunction() async {
resolveTestUnit('''
main() {
useFunction(g: test);
}
useFunction({Function g}) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -2342,14 +2438,14 @@
''');
}
- void test_creationFunction_forFunctionType_dynamicArgument() {
+ test_creationFunction_forFunctionType_dynamicArgument() async {
resolveTestUnit('''
main() {
useFunction(test);
}
useFunction(int g(a, b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -2362,14 +2458,14 @@
''');
}
- void test_creationFunction_forFunctionType_function() {
+ test_creationFunction_forFunctionType_function() async {
resolveTestUnit('''
main() {
useFunction(test);
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -2382,14 +2478,14 @@
''');
}
- void test_creationFunction_forFunctionType_function_namedArgument() {
+ test_creationFunction_forFunctionType_function_namedArgument() async {
resolveTestUnit('''
main() {
useFunction(g: test);
}
useFunction({int g(double a, String b)}) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -2402,7 +2498,7 @@
''');
}
- void test_creationFunction_forFunctionType_importType() {
+ test_creationFunction_forFunctionType_importType() async {
addSource(
'/libA.dart',
r'''
@@ -2422,7 +2518,7 @@
useFunction(test);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
import 'libB.dart';
@@ -2436,7 +2532,7 @@
''');
}
- void test_creationFunction_forFunctionType_method_enclosingClass_static() {
+ test_creationFunction_forFunctionType_method_enclosingClass_static() async {
resolveTestUnit('''
class A {
static foo() {
@@ -2445,7 +2541,7 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -2460,7 +2556,7 @@
''');
}
- void test_creationFunction_forFunctionType_method_enclosingClass_static2() {
+ test_creationFunction_forFunctionType_method_enclosingClass_static2() async {
resolveTestUnit('''
class A {
var f;
@@ -2468,7 +2564,7 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -2482,7 +2578,7 @@
''');
}
- void test_creationFunction_forFunctionType_method_targetClass() {
+ test_creationFunction_forFunctionType_method_targetClass() async {
resolveTestUnit('''
main(A a) {
useFunction(a.test);
@@ -2491,7 +2587,7 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
main(A a) {
@@ -2505,7 +2601,7 @@
''');
}
- void test_creationFunction_forFunctionType_method_targetClass_hasOtherMember() {
+ test_creationFunction_forFunctionType_method_targetClass_hasOtherMember() async {
resolveTestUnit('''
main(A a) {
useFunction(a.test);
@@ -2515,7 +2611,7 @@
}
useFunction(int g(double a, String b)) {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
main(A a) {
@@ -2531,7 +2627,7 @@
''');
}
- void test_creationFunction_forFunctionType_notFunctionType() {
+ test_creationFunction_forFunctionType_notFunctionType() async {
resolveTestUnit('''
main(A a) {
useFunction(a.test);
@@ -2539,11 +2635,11 @@
typedef A();
useFunction(g) {}
''');
- assertNoFix(DartFixKind.CREATE_METHOD);
- assertNoFix(DartFixKind.CREATE_FUNCTION);
+ await assertNoFix(DartFixKind.CREATE_METHOD);
+ await assertNoFix(DartFixKind.CREATE_FUNCTION);
}
- void test_creationFunction_forFunctionType_unknownTarget() {
+ test_creationFunction_forFunctionType_unknownTarget() async {
resolveTestUnit('''
main(A a) {
useFunction(a.test);
@@ -2552,16 +2648,16 @@
}
useFunction(g) {}
''');
- assertNoFix(DartFixKind.CREATE_METHOD);
+ await assertNoFix(DartFixKind.CREATE_METHOD);
}
- void test_expectedToken_semicolon() {
+ test_expectedToken_semicolon() async {
resolveTestUnit('''
main() {
print(0)
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.INSERT_SEMICOLON,
'''
main() {
@@ -2570,7 +2666,23 @@
''');
}
- void test_illegalAsyncReturnType_asyncLibrary_import() {
+ test_illegalAsyncReturnType_adjacentNodes() async {
+ errorFilter = (AnalysisError error) {
+ return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
+ };
+ resolveTestUnit('''
+import 'dart:async';
+var v;int main() async => 0;
+''');
+ await assertHasFix(
+ DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
+ '''
+import 'dart:async';
+var v;Future<int> main() async => 0;
+''');
+ }
+
+ test_illegalAsyncReturnType_asyncLibrary_import() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
};
@@ -2579,7 +2691,7 @@
int main() async {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
'''
library main;
@@ -2589,7 +2701,7 @@
''');
}
- void test_illegalAsyncReturnType_asyncLibrary_usePrefix() {
+ test_illegalAsyncReturnType_asyncLibrary_usePrefix() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
};
@@ -2598,7 +2710,7 @@
int main() async {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
'''
import 'dart:async' as al;
@@ -2607,7 +2719,7 @@
''');
}
- void test_illegalAsyncReturnType_complexTypeName() {
+ test_illegalAsyncReturnType_complexTypeName() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
};
@@ -2616,7 +2728,7 @@
List<int> main() async {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
'''
import 'dart:async';
@@ -2625,7 +2737,7 @@
''');
}
- void test_illegalAsyncReturnType_void() {
+ test_illegalAsyncReturnType_void() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE;
};
@@ -2634,7 +2746,7 @@
void main() async {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
'''
import 'dart:async';
@@ -2643,7 +2755,7 @@
''');
}
- void test_importLibraryPackage_withClass() {
+ test_importLibraryPackage_withClass() async {
_configureMyPkg('''
library my_lib;
class Test {}
@@ -2655,7 +2767,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'package:my_pkg/my_lib.dart';
@@ -2666,7 +2778,7 @@
''');
}
- void test_importLibraryProject_withClass_annotation() {
+ test_importLibraryProject_withClass_annotation() async {
addSource(
'/lib.dart',
'''
@@ -2681,7 +2793,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2692,7 +2804,7 @@
''');
}
- void test_importLibraryProject_withClass_hasOtherLibraryWithPrefix() {
+ test_importLibraryProject_withClass_hasOtherLibraryWithPrefix() async {
testFile = '/project/bin/test.dart';
addSource(
'/project/bin/a.dart',
@@ -2715,7 +2827,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'b.dart' show Two;
@@ -2727,7 +2839,7 @@
''');
}
- void test_importLibraryProject_withClass_inParentFolder() {
+ test_importLibraryProject_withClass_inParentFolder() async {
testFile = '/project/bin/test.dart';
addSource(
'/project/lib.dart',
@@ -2741,7 +2853,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import '../lib.dart';
@@ -2752,7 +2864,7 @@
''');
}
- void test_importLibraryProject_withClass_inRelativeFolder() {
+ test_importLibraryProject_withClass_inRelativeFolder() async {
testFile = '/project/bin/test.dart';
addSource(
'/project/lib/sub/folder/lib.dart',
@@ -2766,7 +2878,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import '../lib/sub/folder/lib.dart';
@@ -2777,7 +2889,7 @@
''');
}
- void test_importLibraryProject_withClass_inSameFolder() {
+ test_importLibraryProject_withClass_inSameFolder() async {
testFile = '/project/bin/test.dart';
addSource(
'/project/bin/lib.dart',
@@ -2791,7 +2903,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2802,7 +2914,7 @@
''');
}
- void test_importLibraryProject_withFunction() {
+ test_importLibraryProject_withFunction() async {
addSource(
'/lib.dart',
'''
@@ -2815,7 +2927,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2826,7 +2938,7 @@
''');
}
- void test_importLibraryProject_withFunction_unresolvedMethod() {
+ test_importLibraryProject_withFunction_unresolvedMethod() async {
addSource(
'/lib.dart',
'''
@@ -2841,7 +2953,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2854,7 +2966,7 @@
''');
}
- void test_importLibraryProject_withFunctionTypeAlias() {
+ test_importLibraryProject_withFunctionTypeAlias() async {
testFile = '/project/bin/test.dart';
addSource(
'/project/bin/lib.dart',
@@ -2868,7 +2980,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2879,7 +2991,7 @@
''');
}
- void test_importLibraryProject_withTopLevelVariable() {
+ test_importLibraryProject_withTopLevelVariable() async {
addSource(
'/lib.dart',
'''
@@ -2892,7 +3004,7 @@
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
import 'lib.dart';
@@ -2903,13 +3015,13 @@
''');
}
- void test_importLibrarySdk_withClass_AsExpression() {
+ test_importLibrarySdk_withClass_AsExpression() async {
resolveTestUnit('''
main(p) {
p as Future;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -2920,13 +3032,13 @@
''');
}
- void test_importLibrarySdk_withClass_invocationTarget() {
+ test_importLibrarySdk_withClass_invocationTarget() async {
resolveTestUnit('''
main() {
Future.wait(null);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -2937,13 +3049,13 @@
''');
}
- void test_importLibrarySdk_withClass_IsExpression() {
+ test_importLibrarySdk_withClass_IsExpression() async {
resolveTestUnit('''
main(p) {
p is Future;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -2954,14 +3066,14 @@
''');
}
- void test_importLibrarySdk_withClass_itemOfList() {
+ test_importLibrarySdk_withClass_itemOfList() async {
resolveTestUnit('''
main() {
var a = [Future];
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -2972,7 +3084,7 @@
''');
}
- void test_importLibrarySdk_withClass_itemOfList_inAnnotation() {
+ test_importLibrarySdk_withClass_itemOfList_inAnnotation() async {
errorFilter = (AnalysisError error) {
return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
};
@@ -2983,7 +3095,7 @@
@MyAnnotation(int, const [Future])
main() {}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -2996,13 +3108,13 @@
''');
}
- void test_importLibrarySdk_withClass_typeAnnotation() {
+ test_importLibrarySdk_withClass_typeAnnotation() async {
resolveTestUnit('''
main() {
Future f = null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -3013,13 +3125,13 @@
''');
}
- void test_importLibrarySdk_withClass_typeAnnotation_PrefixedIdentifier() {
+ test_importLibrarySdk_withClass_typeAnnotation_PrefixedIdentifier() async {
resolveTestUnit('''
main() {
Future.wait;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -3030,13 +3142,13 @@
''');
}
- void test_importLibrarySdk_withClass_typeArgument() {
+ test_importLibrarySdk_withClass_typeArgument() async {
resolveTestUnit('''
main() {
List<Future> futures = [];
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:async';
@@ -3047,14 +3159,14 @@
''');
}
- void test_importLibrarySdk_withTopLevelVariable() {
+ test_importLibrarySdk_withTopLevelVariable() async {
resolveTestUnit('''
main() {
print(PI);
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:math';
@@ -3065,14 +3177,14 @@
''');
}
- void test_importLibrarySdk_withTopLevelVariable_annotation() {
+ test_importLibrarySdk_withTopLevelVariable_annotation() async {
resolveTestUnit('''
@PI
main() {
}
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SDK,
'''
import 'dart:math';
@@ -3083,7 +3195,7 @@
''');
}
- void test_importLibraryShow() {
+ test_importLibraryShow() async {
resolveTestUnit('''
import 'dart:async' show Stream;
main() {
@@ -3091,7 +3203,7 @@
Future f = null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_SHOW,
'''
import 'dart:async' show Future, Stream;
@@ -3102,13 +3214,13 @@
''');
}
- void test_isNotNull() {
+ test_isNotNull() async {
resolveTestUnit('''
main(p) {
p is! Null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.USE_NOT_EQ_NULL,
'''
main(p) {
@@ -3117,13 +3229,13 @@
''');
}
- void test_isNull() {
+ test_isNull() async {
resolveTestUnit('''
main(p) {
p is Null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.USE_EQ_EQ_NULL,
'''
main(p) {
@@ -3132,13 +3244,13 @@
''');
}
- void test_makeEnclosingClassAbstract_declaresAbstractMethod() {
+ test_makeEnclosingClassAbstract_declaresAbstractMethod() async {
resolveTestUnit('''
class A {
m();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.MAKE_CLASS_ABSTRACT,
'''
abstract class A {
@@ -3147,7 +3259,7 @@
''');
}
- void test_makeEnclosingClassAbstract_inheritsAbstractMethod() {
+ test_makeEnclosingClassAbstract_inheritsAbstractMethod() async {
resolveTestUnit('''
abstract class A {
m();
@@ -3155,7 +3267,7 @@
class B extends A {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.MAKE_CLASS_ABSTRACT,
'''
abstract class A {
@@ -3166,18 +3278,18 @@
''');
}
- void test_noException_1() {
+ test_noException_1() async {
resolveTestUnit('''
main(p) {
p i s Null;
}''');
List<AnalysisError> errors = context.computeErrors(testSource);
for (var error in errors) {
- _computeFixes(error);
+ await _computeFixes(error);
}
}
- void test_nonBoolCondition_addNotNull() {
+ test_nonBoolCondition_addNotNull() async {
resolveTestUnit('''
main(String p) {
if (p) {
@@ -3185,7 +3297,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.ADD_NE_NULL,
'''
main(String p) {
@@ -3196,7 +3308,7 @@
''');
}
- void test_removeDeadCode_condition() {
+ test_removeDeadCode_condition() async {
resolveTestUnit('''
main(int p) {
if (true || p > 5) {
@@ -3204,7 +3316,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_DEAD_CODE,
'''
main(int p) {
@@ -3215,7 +3327,7 @@
''');
}
- void test_removeDeadCode_statements_one() {
+ test_removeDeadCode_statements_one() async {
resolveTestUnit('''
int main() {
print(0);
@@ -3223,7 +3335,7 @@
print(1);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_DEAD_CODE,
'''
int main() {
@@ -3233,7 +3345,7 @@
''');
}
- void test_removeDeadCode_statements_two() {
+ test_removeDeadCode_statements_two() async {
resolveTestUnit('''
int main() {
print(0);
@@ -3242,7 +3354,7 @@
print(2);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_DEAD_CODE,
'''
int main() {
@@ -3252,13 +3364,13 @@
''');
}
- void test_removeParentheses_inGetterDeclaration() {
+ test_removeParentheses_inGetterDeclaration() async {
resolveTestUnit('''
class A {
int get foo() => 0;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_PARAMETERS_IN_GETTER_DECLARATION,
'''
class A {
@@ -3267,7 +3379,7 @@
''');
}
- void test_removeParentheses_inGetterInvocation() {
+ test_removeParentheses_inGetterInvocation() async {
resolveTestUnit('''
class A {
int get foo => 0;
@@ -3276,7 +3388,7 @@
a.foo();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_PARENTHESIS_IN_GETTER_INVOCATION,
'''
class A {
@@ -3288,7 +3400,7 @@
''');
}
- void test_removeUnnecessaryCast_assignment() {
+ test_removeUnnecessaryCast_assignment() async {
resolveTestUnit('''
main(Object p) {
if (p is String) {
@@ -3296,7 +3408,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNNECESSARY_CAST,
'''
main(Object p) {
@@ -3307,7 +3419,7 @@
''');
}
- void test_removeUnusedCatchClause() {
+ test_removeUnusedCatchClause() async {
errorFilter = (AnalysisError error) => true;
resolveTestUnit('''
main() {
@@ -3317,7 +3429,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNUSED_CATCH_CLAUSE,
'''
main() {
@@ -3329,7 +3441,7 @@
''');
}
- void test_removeUnusedCatchStack() {
+ test_removeUnusedCatchStack() async {
errorFilter = (AnalysisError error) => true;
resolveTestUnit('''
main() {
@@ -3339,7 +3451,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNUSED_CATCH_STACK,
'''
main() {
@@ -3351,13 +3463,13 @@
''');
}
- void test_removeUnusedImport() {
+ test_removeUnusedImport() async {
resolveTestUnit('''
import 'dart:math';
main() {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNUSED_IMPORT,
'''
main() {
@@ -3365,7 +3477,7 @@
''');
}
- void test_removeUnusedImport_anotherImportOnLine() {
+ test_removeUnusedImport_anotherImportOnLine() async {
resolveTestUnit('''
import 'dart:math'; import 'dart:async';
@@ -3373,7 +3485,7 @@
Future f;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNUSED_IMPORT,
'''
import 'dart:async';
@@ -3384,14 +3496,14 @@
''');
}
- void test_removeUnusedImport_severalLines() {
+ test_removeUnusedImport_severalLines() async {
resolveTestUnit('''
import
'dart:math';
main() {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REMOVE_UNUSED_IMPORT,
'''
main() {
@@ -3399,34 +3511,34 @@
''');
}
- void test_replaceImportUri_inProject() {
+ test_replaceImportUri_inProject() async {
testFile = '/project/bin/test.dart';
addSource('/project/foo/bar/lib.dart', '');
resolveTestUnit('''
import 'no/matter/lib.dart';
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_IMPORT_URI,
'''
import '../foo/bar/lib.dart';
''');
}
- void test_replaceImportUri_package() {
+ test_replaceImportUri_package() async {
_configureMyPkg('');
resolveTestUnit('''
import 'no/matter/my_lib.dart';
''');
performAllAnalysisTasks();
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_IMPORT_URI,
'''
import 'package:my_pkg/my_lib.dart';
''');
}
- void test_replaceVarWithDynamic() {
+ test_replaceVarWithDynamic() async {
errorFilter = (AnalysisError error) {
return error.errorCode == ParserErrorCode.VAR_AS_TYPE_NAME;
};
@@ -3435,7 +3547,7 @@
Map<String, var> m;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.REPLACE_VAR_WITH_DYNAMIC,
'''
class A {
@@ -3444,14 +3556,14 @@
''');
}
- void test_replaceWithConstInstanceCreation() {
+ test_replaceWithConstInstanceCreation() async {
resolveTestUnit('''
class A {
const A();
}
const a = new A();
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.USE_CONST,
'''
class A {
@@ -3461,13 +3573,13 @@
''');
}
- void test_undefinedClass_useSimilar_fromImport() {
+ test_undefinedClass_useSimilar_fromImport() async {
resolveTestUnit('''
main() {
Stirng s = 'abc';
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
main() {
@@ -3476,14 +3588,14 @@
''');
}
- void test_undefinedClass_useSimilar_fromThisLibrary() {
+ test_undefinedClass_useSimilar_fromThisLibrary() async {
resolveTestUnit('''
class MyClass {}
main() {
MyCalss v = null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class MyClass {}
@@ -3493,14 +3605,14 @@
''');
}
- void test_undefinedFunction_create_dynamicArgument() {
+ test_undefinedFunction_create_dynamicArgument() async {
resolveTestUnit('''
main() {
dynamic v;
test(v);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3513,13 +3625,13 @@
''');
}
- void test_undefinedFunction_create_dynamicReturnType() {
+ test_undefinedFunction_create_dynamicReturnType() async {
resolveTestUnit('''
main() {
dynamic v = test();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3531,13 +3643,13 @@
''');
}
- void test_undefinedFunction_create_fromFunction() {
+ test_undefinedFunction_create_fromFunction() async {
resolveTestUnit('''
main() {
int v = myUndefinedFunction(1, 2.0, '3');
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3549,7 +3661,7 @@
''');
}
- void test_undefinedFunction_create_fromMethod() {
+ test_undefinedFunction_create_fromMethod() async {
resolveTestUnit('''
class A {
main() {
@@ -3557,7 +3669,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
class A {
@@ -3571,7 +3683,7 @@
''');
}
- void test_undefinedFunction_create_generic_BAD() {
+ test_undefinedFunction_create_generic_BAD() async {
resolveTestUnit('''
class A<T> {
Map<int, T> items;
@@ -3580,7 +3692,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
class A<T> {
@@ -3595,7 +3707,7 @@
''');
}
- void test_undefinedFunction_create_generic_OK() {
+ test_undefinedFunction_create_generic_OK() async {
resolveTestUnit('''
class A {
List<int> items;
@@ -3604,7 +3716,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
class A {
@@ -3619,7 +3731,7 @@
''');
}
- void test_undefinedFunction_create_importType() {
+ test_undefinedFunction_create_importType() async {
addSource(
'/lib.dart',
r'''
@@ -3633,7 +3745,7 @@
test(getFuture());
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
import 'lib.dart';
@@ -3647,13 +3759,13 @@
''');
}
- void test_undefinedFunction_create_nullArgument() {
+ test_undefinedFunction_create_nullArgument() async {
resolveTestUnit('''
main() {
test(null);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3665,29 +3777,31 @@
''');
}
- void test_undefinedFunction_create_returnType_bool_expressions() {
- assert_undefinedFunction_create_returnType_bool("!test();");
- assert_undefinedFunction_create_returnType_bool("b && test();");
- assert_undefinedFunction_create_returnType_bool("test() && b;");
- assert_undefinedFunction_create_returnType_bool("b || test();");
- assert_undefinedFunction_create_returnType_bool("test() || b;");
+ test_undefinedFunction_create_returnType_bool_expressions() async {
+ await assert_undefinedFunction_create_returnType_bool("!test();");
+ await assert_undefinedFunction_create_returnType_bool("b && test();");
+ await assert_undefinedFunction_create_returnType_bool("test() && b;");
+ await assert_undefinedFunction_create_returnType_bool("b || test();");
+ await assert_undefinedFunction_create_returnType_bool("test() || b;");
}
- void test_undefinedFunction_create_returnType_bool_statements() {
- assert_undefinedFunction_create_returnType_bool("assert ( test() );");
- assert_undefinedFunction_create_returnType_bool("if ( test() ) {}");
- assert_undefinedFunction_create_returnType_bool("while ( test() ) {}");
- assert_undefinedFunction_create_returnType_bool("do {} while ( test() );");
+ test_undefinedFunction_create_returnType_bool_statements() async {
+ await assert_undefinedFunction_create_returnType_bool("assert ( test() );");
+ await assert_undefinedFunction_create_returnType_bool("if ( test() ) {}");
+ await assert_undefinedFunction_create_returnType_bool(
+ "while ( test() ) {}");
+ await assert_undefinedFunction_create_returnType_bool(
+ "do {} while ( test() );");
}
- void test_undefinedFunction_create_returnType_fromAssignment_eq() {
+ test_undefinedFunction_create_returnType_fromAssignment_eq() async {
resolveTestUnit('''
main() {
int v;
v = myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3700,14 +3814,14 @@
''');
}
- void test_undefinedFunction_create_returnType_fromAssignment_plusEq() {
+ test_undefinedFunction_create_returnType_fromAssignment_plusEq() async {
resolveTestUnit('''
main() {
int v;
v += myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3720,13 +3834,13 @@
''');
}
- void test_undefinedFunction_create_returnType_fromBinary_right() {
+ test_undefinedFunction_create_returnType_fromBinary_right() async {
resolveTestUnit('''
main() {
0 + myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3738,13 +3852,13 @@
''');
}
- void test_undefinedFunction_create_returnType_fromInitializer() {
+ test_undefinedFunction_create_returnType_fromInitializer() async {
resolveTestUnit('''
main() {
int v = myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3756,14 +3870,14 @@
''');
}
- void test_undefinedFunction_create_returnType_fromInvocationArgument() {
+ test_undefinedFunction_create_returnType_fromInvocationArgument() async {
resolveTestUnit('''
foo(int p) {}
main() {
foo( myUndefinedFunction() );
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
foo(int p) {}
@@ -3776,13 +3890,13 @@
''');
}
- void test_undefinedFunction_create_returnType_fromReturn() {
+ test_undefinedFunction_create_returnType_fromReturn() async {
resolveTestUnit('''
int main() {
return myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
int main() {
@@ -3794,13 +3908,13 @@
''');
}
- void test_undefinedFunction_create_returnType_void() {
+ test_undefinedFunction_create_returnType_void() async {
resolveTestUnit('''
main() {
myUndefinedFunction();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
main() {
@@ -3812,13 +3926,13 @@
''');
}
- void test_undefinedFunction_useSimilar_fromImport() {
+ test_undefinedFunction_useSimilar_fromImport() async {
resolveTestUnit('''
main() {
pritn(0);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
main() {
@@ -3827,14 +3941,14 @@
''');
}
- void test_undefinedFunction_useSimilar_thisLibrary() {
+ test_undefinedFunction_useSimilar_thisLibrary() async {
resolveTestUnit('''
myFunction() {}
main() {
myFuntcion();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
myFunction() {}
@@ -3844,7 +3958,7 @@
''');
}
- void test_undefinedGetter_useSimilar_hint() {
+ test_undefinedGetter_useSimilar_hint() async {
resolveTestUnit('''
class A {
int myField;
@@ -3854,7 +3968,7 @@
print(x.myFild);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -3867,7 +3981,7 @@
''');
}
- void test_undefinedGetter_useSimilar_qualified() {
+ test_undefinedGetter_useSimilar_qualified() async {
resolveTestUnit('''
class A {
int myField;
@@ -3876,7 +3990,7 @@
print(a.myFild);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -3888,7 +4002,7 @@
''');
}
- void test_undefinedGetter_useSimilar_qualified_static() {
+ test_undefinedGetter_useSimilar_qualified_static() async {
resolveTestUnit('''
class A {
static int MY_NAME = 1;
@@ -3897,7 +4011,7 @@
A.MY_NAM;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -3909,7 +4023,7 @@
''');
}
- void test_undefinedGetter_useSimilar_unqualified() {
+ test_undefinedGetter_useSimilar_unqualified() async {
resolveTestUnit('''
class A {
int myField;
@@ -3918,7 +4032,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -3930,16 +4044,16 @@
''');
}
- void test_undefinedMethod_create_BAD_inSDK() {
+ test_undefinedMethod_create_BAD_inSDK() async {
resolveTestUnit('''
main() {
List.foo();
}
''');
- assertNoFix(DartFixKind.CREATE_METHOD);
+ await assertNoFix(DartFixKind.CREATE_METHOD);
}
- void test_undefinedMethod_create_generic_BAD_argumentType() {
+ test_undefinedMethod_create_generic_BAD_argumentType() async {
resolveTestUnit('''
class A<T> {
B b;
@@ -3952,7 +4066,7 @@
class B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A<T> {
@@ -3970,7 +4084,7 @@
''');
}
- void test_undefinedMethod_create_generic_BAD_returnType() {
+ test_undefinedMethod_create_generic_BAD_returnType() async {
resolveTestUnit('''
class A<T> {
main() {
@@ -3981,7 +4095,7 @@
class B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A<T> {
@@ -3997,7 +4111,7 @@
''');
}
- void test_undefinedMethod_create_generic_OK_literal() {
+ test_undefinedMethod_create_generic_OK_literal() async {
resolveTestUnit('''
class A {
B b;
@@ -4010,7 +4124,7 @@
class B {
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4028,7 +4142,7 @@
''');
}
- void test_undefinedMethod_create_generic_OK_local() {
+ test_undefinedMethod_create_generic_OK_local() async {
resolveTestUnit('''
class A<T> {
List<T> items;
@@ -4037,7 +4151,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A<T> {
@@ -4052,7 +4166,7 @@
''');
}
- void test_undefinedMethod_createQualified_fromClass() {
+ test_undefinedMethod_createQualified_fromClass() async {
resolveTestUnit('''
class A {
}
@@ -4060,7 +4174,7 @@
A.myUndefinedMethod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4073,7 +4187,7 @@
''');
}
- void test_undefinedMethod_createQualified_fromClass_hasOtherMember() {
+ test_undefinedMethod_createQualified_fromClass_hasOtherMember() async {
resolveTestUnit('''
class A {
foo() {}
@@ -4082,7 +4196,7 @@
A.myUndefinedMethod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4097,7 +4211,7 @@
''');
}
- void test_undefinedMethod_createQualified_fromInstance() {
+ test_undefinedMethod_createQualified_fromInstance() async {
resolveTestUnit('''
class A {
}
@@ -4105,7 +4219,7 @@
a.myUndefinedMethod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4118,26 +4232,26 @@
''');
}
- void test_undefinedMethod_createQualified_targetIsFunctionType() {
+ test_undefinedMethod_createQualified_targetIsFunctionType() async {
resolveTestUnit('''
typedef A();
main() {
A.myUndefinedMethod();
}
''');
- assertNoFix(DartFixKind.CREATE_METHOD);
+ await assertNoFix(DartFixKind.CREATE_METHOD);
}
- void test_undefinedMethod_createQualified_targetIsUnresolved() {
+ test_undefinedMethod_createQualified_targetIsUnresolved() async {
resolveTestUnit('''
main() {
NoSuchClass.myUndefinedMethod();
}
''');
- assertNoFix(DartFixKind.CREATE_METHOD);
+ await assertNoFix(DartFixKind.CREATE_METHOD);
}
- void test_undefinedMethod_createUnqualified_parameters() {
+ test_undefinedMethod_createUnqualified_parameters() async {
resolveTestUnit('''
class A {
main() {
@@ -4145,7 +4259,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4183,7 +4297,51 @@
_assertLinkedGroup(change.linkedEditGroups[index++], ['s)']);
}
- void test_undefinedMethod_createUnqualified_returnType() {
+ test_undefinedMethod_createUnqualified_parameters_named() async {
+ resolveTestUnit('''
+class A {
+ main() {
+ myUndefinedMethod(0, bbb: 1.0, ccc: '2');
+ }
+}
+''');
+ await assertHasFix(
+ DartFixKind.CREATE_METHOD,
+ '''
+class A {
+ main() {
+ myUndefinedMethod(0, bbb: 1.0, ccc: '2');
+ }
+
+ void myUndefinedMethod(int i, {double bbb, String ccc}) {
+ }
+}
+''');
+ // linked positions
+ int index = 0;
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++], ['void myUndefinedMethod(']);
+ _assertLinkedGroup(change.linkedEditGroups[index++],
+ ['myUndefinedMethod(0', 'myUndefinedMethod(int']);
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['int i'],
+ expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+ ['int', 'num', 'Object', 'Comparable']));
+ _assertLinkedGroup(change.linkedEditGroups[index++], ['i,']);
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['double bbb'],
+ expectedSuggestions(LinkedEditSuggestionKind.TYPE,
+ ['double', 'num', 'Object', 'Comparable']));
+ _assertLinkedGroup(
+ change.linkedEditGroups[index++],
+ ['String ccc'],
+ expectedSuggestions(
+ LinkedEditSuggestionKind.TYPE, ['String', 'Object', 'Comparable']));
+ }
+
+ test_undefinedMethod_createUnqualified_returnType() async {
resolveTestUnit('''
class A {
main() {
@@ -4191,7 +4349,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4209,13 +4367,13 @@
['myUndefinedMethod();', 'myUndefinedMethod() {']);
}
- void test_undefinedMethod_createUnqualified_staticFromField() {
+ test_undefinedMethod_createUnqualified_staticFromField() async {
resolveTestUnit('''
class A {
static var f = myUndefinedMethod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4227,7 +4385,7 @@
''');
}
- void test_undefinedMethod_createUnqualified_staticFromMethod() {
+ test_undefinedMethod_createUnqualified_staticFromMethod() async {
resolveTestUnit('''
class A {
static main() {
@@ -4235,7 +4393,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4249,7 +4407,7 @@
''');
}
- void test_undefinedMethod_hint_createQualified_fromInstance() {
+ test_undefinedMethod_hint_createQualified_fromInstance() async {
resolveTestUnit('''
class A {
}
@@ -4258,7 +4416,7 @@
a.myUndefinedMethod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CREATE_METHOD,
'''
class A {
@@ -4272,7 +4430,7 @@
''');
}
- void test_undefinedMethod_parameterType_differentPrefixInTargetUnit() {
+ test_undefinedMethod_parameterType_differentPrefixInTargetUnit() async {
String code2 = r'''
library test2;
import 'test3.dart' as bbb;
@@ -4295,7 +4453,7 @@
}
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_METHOD, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_METHOD, error);
change = fix.change;
// apply to "test2.dart"
List<SourceFileEdit> fileEdits = change.edits;
@@ -4315,7 +4473,7 @@
''');
}
- void test_undefinedMethod_parameterType_inTargetUnit() {
+ test_undefinedMethod_parameterType_inTargetUnit() async {
String code2 = r'''
library test2;
class D {
@@ -4331,7 +4489,7 @@
}
''');
AnalysisError error = _findErrorToFix();
- fix = _assertHasFix(DartFixKind.CREATE_METHOD, error);
+ fix = await _assertHasFix(DartFixKind.CREATE_METHOD, error);
change = fix.change;
// apply to "test2.dart"
List<SourceFileEdit> fileEdits = change.edits;
@@ -4350,16 +4508,16 @@
''');
}
- void test_undefinedMethod_useSimilar_ignoreOperators() {
+ test_undefinedMethod_useSimilar_ignoreOperators() async {
resolveTestUnit('''
main(Object object) {
object.then();
}
''');
- assertNoFix(DartFixKind.CHANGE_TO);
+ await assertNoFix(DartFixKind.CHANGE_TO);
}
- void test_undefinedMethod_useSimilar_qualified() {
+ test_undefinedMethod_useSimilar_qualified() async {
resolveTestUnit('''
class A {
myMethod() {}
@@ -4369,7 +4527,7 @@
a.myMehtod();
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4382,7 +4540,7 @@
''');
}
- void test_undefinedMethod_useSimilar_unqualified_superClass() {
+ test_undefinedMethod_useSimilar_unqualified_superClass() async {
resolveTestUnit('''
class A {
myMethod() {}
@@ -4393,7 +4551,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4407,7 +4565,7 @@
''');
}
- void test_undefinedMethod_useSimilar_unqualified_thisClass() {
+ test_undefinedMethod_useSimilar_unqualified_thisClass() async {
resolveTestUnit('''
class A {
myMethod() {}
@@ -4416,7 +4574,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4428,7 +4586,7 @@
''');
}
- void test_undefinedSetter_useSimilar_hint() {
+ test_undefinedSetter_useSimilar_hint() async {
resolveTestUnit('''
class A {
int myField;
@@ -4438,7 +4596,7 @@
x.myFild = 42;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4451,7 +4609,7 @@
''');
}
- void test_undefinedSetter_useSimilar_qualified() {
+ test_undefinedSetter_useSimilar_qualified() async {
resolveTestUnit('''
class A {
int myField;
@@ -4460,7 +4618,7 @@
a.myFild = 42;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4472,7 +4630,7 @@
''');
}
- void test_undefinedSetter_useSimilar_unqualified() {
+ test_undefinedSetter_useSimilar_unqualified() async {
resolveTestUnit('''
class A {
int myField;
@@ -4481,7 +4639,7 @@
}
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.CHANGE_TO,
'''
class A {
@@ -4493,7 +4651,7 @@
''');
}
- void test_useEffectiveIntegerDivision() {
+ test_useEffectiveIntegerDivision() async {
resolveTestUnit('''
main() {
var a = 5;
@@ -4501,7 +4659,7 @@
print((a / b).toInt());
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.USE_EFFECTIVE_INTEGER_DIVISION,
'''
main() {
@@ -4512,7 +4670,7 @@
''');
}
- void test_useImportPrefix_withClass() {
+ test_useImportPrefix_withClass() async {
resolveTestUnit('''
import 'dart:async' as pref;
main() {
@@ -4520,7 +4678,7 @@
Future f = null;
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PREFIX,
'''
import 'dart:async' as pref;
@@ -4531,7 +4689,7 @@
''');
}
- void test_useImportPrefix_withTopLevelVariable() {
+ test_useImportPrefix_withTopLevelVariable() async {
resolveTestUnit('''
import 'dart:math' as pref;
main() {
@@ -4539,7 +4697,7 @@
print(PI);
}
''');
- assertHasFix(
+ await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PREFIX,
'''
import 'dart:math' as pref;
@@ -4553,8 +4711,8 @@
/**
* Computes fixes and verifies that there is a fix of the given kind.
*/
- Fix _assertHasFix(FixKind kind, AnalysisError error) {
- List<Fix> fixes = _computeFixes(error);
+ Future<Fix> _assertHasFix(FixKind kind, AnalysisError error) async {
+ List<Fix> fixes = await _computeFixes(error);
for (Fix fix in fixes) {
if (fix.kind == kind) {
return fix;
@@ -4575,8 +4733,10 @@
/**
* Computes fixes for the given [error] in [testUnit].
*/
- List<Fix> _computeFixes(AnalysisError error) {
- FixProcessor processor = new FixProcessor(provider, testUnit, error);
+ Future<List<Fix>> _computeFixes(AnalysisError error) async {
+ DartFixContext dartContext = new DartFixContextImpl(
+ new FixContextImpl(provider, context, error), testUnit);
+ FixProcessor processor = new FixProcessor(dartContext);
return processor.compute();
}
diff --git a/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart b/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
index 69ccf4b..2c1b7b9 100644
--- a/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
+++ b/pkg/analysis_server/test/services/dependencies/library_dependencies_test.dart
@@ -34,7 +34,7 @@
// 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
diff --git a/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart b/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart
new file mode 100644
index 0000000..b040926
--- /dev/null
+++ b/pkg/analysis_server/test/services/dependencies/reachable_source_collector_test.dart
@@ -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'
+ ]));
+ }
+}
diff --git a/pkg/analysis_server/test/services/dependencies/test_all.dart b/pkg/analysis_server/test/services/dependencies/test_all.dart
index 1874a07..b26ac82 100644
--- a/pkg/analysis_server/test/services/dependencies/test_all.dart
+++ b/pkg/analysis_server/test/services/dependencies/test_all.dart
@@ -7,12 +7,14 @@
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();
});
}
diff --git a/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart b/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
index 1830a28..9ba6cae 100644
--- a/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
+++ b/pkg/analysis_server/test/services/index/dart_index_contributor_test.dart
@@ -4,7 +4,7 @@
library test.services.src.index.dart_index_contributor;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/index_contributor.dart';
import 'package:analysis_server/src/services/index/index_store.dart';
@@ -94,27 +94,6 @@
});
}
- void test_isReferencedBy_PrefixElement() {
- _indexTestUnit('''
-import 'dart:async' as ppp;
-main() {
- ppp.Future a;
- ppp.Stream b;
-}
-''');
- // prepare elements
- PrefixElement element = findNodeElementAtString('ppp;');
- Element elementA = findElement('a');
- Element elementB = findElement('b');
- IndexableElement indexable = new IndexableElement(element);
- // verify
- _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
- _expectedLocation(elementA, 'ppp.Future'));
- _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
- _expectedLocation(elementB, 'ppp.Stream'));
- _assertNoRecordedRelation(indexable, null, _expectedLocation(null, 'ppp;'));
- }
-
void test_bad_unresolvedFieldFormalParameter() {
verifyNoTestUnitErrors = false;
_indexTestUnit('''
@@ -1423,6 +1402,27 @@
_expectedLocation(mainElement, 'p: 1'));
}
+ void test_isReferencedBy_PrefixElement() {
+ _indexTestUnit('''
+import 'dart:async' as ppp;
+main() {
+ ppp.Future a;
+ ppp.Stream b;
+}
+''');
+ // prepare elements
+ PrefixElement element = findNodeElementAtString('ppp;');
+ Element elementA = findElement('a');
+ Element elementB = findElement('b');
+ IndexableElement indexable = new IndexableElement(element);
+ // verify
+ _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
+ _expectedLocation(elementA, 'ppp.Future'));
+ _assertRecordedRelation(indexable, IndexConstants.IS_REFERENCED_BY,
+ _expectedLocation(elementB, 'ppp.Stream'));
+ _assertNoRecordedRelation(indexable, null, _expectedLocation(null, 'ppp;'));
+ }
+
void test_isReferencedBy_TopLevelVariableElement() {
addSource(
'/lib.dart',
diff --git a/pkg/analysis_server/test/services/index/store/codec_test.dart b/pkg/analysis_server/test/services/index/store/codec_test.dart
index cfc6b97..15adf15 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -4,7 +4,7 @@
library test.services.src.index.store.codec;
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
import 'package:analysis_server/src/services/index/store/codec.dart';
diff --git a/pkg/analysis_server/test/services/index/store/split_store_test.dart b/pkg/analysis_server/test/services/index/store/split_store_test.dart
index ab91ca6..17c7e8b 100644
--- a/pkg/analysis_server/test/services/index/store/split_store_test.dart
+++ b/pkg/analysis_server/test/services/index/store/split_store_test.dart
@@ -6,7 +6,7 @@
import 'dart:async';
-import 'package:analysis_server/plugin/index/index_core.dart';
+import 'package:analysis_server/src/provisional/index/index_core.dart';
import 'package:analysis_server/src/services/index/index.dart';
import 'package:analysis_server/src/services/index/indexable_element.dart';
import 'package:analysis_server/src/services/index/store/codec.dart';
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index 4dfb55d..46a6e67 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -69,17 +69,16 @@
expectedMessage: 'Cannot extract the left-hand side of an assignment.');
}
- test_checkInitialConditions_methodName_reference() async {
+ test_checkInitialConditions_namePartOfDeclaration_function() async {
indexTestUnit('''
main() {
- main();
}
''');
- _createRefactoringWithSuffix('main', '();');
+ _createRefactoringWithSuffix('main', '()');
// check conditions
RefactoringStatus status = await refactoring.checkAllConditions();
assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
- expectedMessage: 'Cannot extract a single method name.');
+ expectedMessage: 'Cannot extract the name part of a declaration.');
}
test_checkInitialConditions_namePartOfDeclaration_variable() async {
@@ -333,16 +332,40 @@
_createRefactoring(testCode.indexOf('bb * 2'), 0);
// check conditions
await refactoring.checkInitialConditions();
- List<String> subExpressions = <String>[];
- for (int i = 0; i < refactoring.coveringExpressionOffsets.length; i++) {
- int offset = refactoring.coveringExpressionOffsets[i];
- int length = refactoring.coveringExpressionLengths[i];
- subExpressions.add(testCode.substring(offset, offset + length));
- }
+ List<String> subExpressions = _getCoveringExpressions();
expect(subExpressions,
['bbb', 'bbb * 2', 'aaa + bbb * 2', 'aaa + bbb * 2 + 3']);
}
+ test_coveringExpressions_inArgumentList() async {
+ indexTestUnit('''
+main() {
+ foo(111 + 222);
+}
+int foo(int x) => x;
+''');
+ _createRefactoring(testCode.indexOf('11 +'), 0);
+ // check conditions
+ await refactoring.checkInitialConditions();
+ List<String> subExpressions = _getCoveringExpressions();
+ expect(subExpressions, ['111', '111 + 222', 'foo(111 + 222)']);
+ }
+
+ test_coveringExpressions_skipAssignments() async {
+ indexTestUnit('''
+main() {
+ int v;
+ foo(v = 111 + 222);
+}
+int foo(x) => 42;
+''');
+ _createRefactoring(testCode.indexOf('11 +'), 0);
+ // check conditions
+ await refactoring.checkInitialConditions();
+ List<String> subExpressions = _getCoveringExpressions();
+ expect(subExpressions, ['111', '111 + 222', 'foo(v = 111 + 222)']);
+ }
+
test_fragmentExpression() {
indexTestUnit('''
main() {
@@ -859,6 +882,24 @@
''');
}
+ test_singleExpression_methodName_reference() async {
+ indexTestUnit('''
+main() {
+ var v = foo().length;
+}
+String foo() => '';
+''');
+ _createRefactoringWithSuffix('foo', '().');
+ // apply refactoring
+ return _assertSuccessfulRefactoring('''
+main() {
+ var res = foo();
+ var v = res.length;
+}
+String foo() => '';
+''');
+ }
+
test_singleExpression_nameOfProperty_prefixedIdentifier() async {
indexTestUnit('''
main(p) {
@@ -894,7 +935,7 @@
}
/**
- * Here we use knowledge how exactly `1 + 2 + 3 + 41 is parsed. We know that
+ * Here we use knowledge how exactly `1 + 2 + 3 + 4` is parsed. We know that
* `1 + 2` will be a separate and complete binary expression, so it can be
* handled as a single expression.
*/
@@ -1036,4 +1077,14 @@
int length = selectionSearch.length;
_createRefactoring(offset, length);
}
+
+ List<String> _getCoveringExpressions() {
+ List<String> subExpressions = <String>[];
+ for (int i = 0; i < refactoring.coveringExpressionOffsets.length; i++) {
+ int offset = refactoring.coveringExpressionOffsets[i];
+ int length = refactoring.coveringExpressionLengths[i];
+ subExpressions.add(testCode.substring(offset, offset + length));
+ }
+ return subExpressions;
+ }
}
diff --git a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
index 2c1d252..9aa321b 100644
--- a/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
+++ b/pkg/analysis_server/test/source/caching_put_package_map_provider_test.dart
@@ -49,7 +49,9 @@
for (String path in inputFiles) {
resProvider.newFile(path, '');
}
- return resProvider.getResource(inputFiles[0]).parent;
+ Folder projectFolder = resProvider.getResource(inputFiles[0]).parent;
+ resProvider.newFile(projectFolder.path + '/pubspec.lock', '');
+ return projectFolder;
}
int mockWriteFile(File cacheFile, String content) {
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
index 43adc4e..4eb855f 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_core_test.dart
@@ -4,8 +4,8 @@
library analysis_server.test.src.utilities.change_builder_core_test;
-import 'package:analysis_server/plugin/edit/utilities/change_builder_core.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_core.dart';
import 'package:analysis_server/src/utilities/change_builder_core.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
diff --git a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
index 7c6442b..5db934d 100644
--- a/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
+++ b/pkg/analysis_server/test/src/utilities/change_builder_dart_test.dart
@@ -4,8 +4,8 @@
library analysis_server.test.src.utilities.change_builder_dart_test;
-import 'package:analysis_server/plugin/edit/utilities/change_builder_dart.dart';
import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/provisional/edit/utilities/change_builder_dart.dart';
import 'package:analysis_server/src/utilities/change_builder_dart.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/test/stress/replay/operation.dart b/pkg/analysis_server/test/stress/replay/operation.dart
new file mode 100644
index 0000000..d7af722
--- /dev/null
+++ b/pkg/analysis_server/test/stress/replay/operation.dart
@@ -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.
+
+/**
+ * Operations to be performed during the simulation.
+ */
+library analysis_server.test.stress.replay.replay;
+
+import '../utilities/server.dart';
+
+/**
+ * An operation that will send an 'analysis.updateContent' request.
+ */
+class AnalysisUpdateContent extends ServerOperation {
+ /**
+ * The path of the file whose content is being updated.
+ */
+ String filePath;
+
+ /**
+ * The overlay used to update the content.
+ */
+ dynamic overlay;
+
+ /**
+ * Initialize an operation to send an 'analysis.updateContent' request with
+ * the given [filePath] and [overlay] as parameters.
+ */
+ AnalysisUpdateContent(this.filePath, this.overlay);
+
+ @override
+ void perform(Server server) {
+ server.sendAnalysisUpdateContent({filePath: overlay});
+// if (overlay is ChangeContentOverlay) {
+// List<SourceEdit> edits = (overlay as ChangeContentOverlay).edits;
+// if (edits.length == 1) {
+// SourceEdit edit = edits[0];
+// if (edit.replacement.endsWith('.')) {
+// int offset = edit.offset + edit.replacement.length - 1;
+// server.sendCompletionGetSuggestions(filePath, offset);
+// }
+// }
+// }
+ }
+}
+
+/**
+ * An operation to be performed during the simulation.
+ */
+abstract class ServerOperation {
+ /**
+ * Perform this operation by communicating with the given [server].
+ */
+ void perform(Server server);
+}
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
new file mode 100644
index 0000000..37de911
--- /dev/null
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -0,0 +1,467 @@
+// 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.
+
+/**
+ * A stress test for the analysis server.
+ */
+library analysis_server.test.stress.replay.replay;
+
+import 'dart:async';
+import 'dart:io';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/util/glob.dart';
+import 'package:args/args.dart';
+import 'package:path/path.dart' as path;
+
+import '../utilities/git.dart';
+import '../utilities/server.dart';
+import 'operation.dart';
+
+/**
+ * Run the simulation based on the given command-line [arguments].
+ */
+Future main(List<String> arguments) async {
+ Driver driver = new Driver();
+ await driver.run(arguments);
+}
+
+/**
+ * The driver class that runs the simulation.
+ */
+class Driver {
+ /**
+ * The name of the command-line flag that will print help text.
+ */
+ static String HELP_FLAG_NAME = 'help';
+
+ /**
+ * The name of the pubspec file.
+ */
+ static const String PUBSPEC_FILE_NAME = 'pubspec.yaml';
+
+ /**
+ * The name of the branch used to clean-up after making temporary changes.
+ */
+ static const String TEMP_BRANCH_NAME = 'temp';
+
+ /**
+ * The absolute path of the repository.
+ */
+ String repositoryPath;
+
+ /**
+ * The absolute paths to the analysis roots.
+ */
+ List<String> analysisRoots;
+
+ /**
+ * The git repository.
+ */
+ GitRepository repository;
+
+ /**
+ * The connection to the analysis server.
+ */
+ Server server = new Server();
+
+ /**
+ * A list of the glob patterns used to identify the files being analyzed by
+ * the server.
+ */
+ List<Glob> fileGlobs;
+
+ /**
+ * An object gathering statistics about the simulation.
+ */
+ Statistics statistics;
+
+ /**
+ * Initialize a newly created driver.
+ */
+ Driver() {
+ statistics = new Statistics(this);
+ }
+
+ /**
+ * Run the test based on the given command-line arguments ([args]).
+ */
+ Future run(List<String> args) async {
+ //
+ // Process the command-line arguments.
+ //
+ ArgParser parser = _createArgParser();
+ ArgResults results;
+ try {
+ results = parser.parse(args);
+ } catch (exception) {
+ _showUsage(parser);
+ return null;
+ }
+
+ if (results[HELP_FLAG_NAME]) {
+ _showUsage(parser);
+ return null;
+ }
+
+ List<String> arguments = results.arguments;
+ if (arguments.length < 2) {
+ _showUsage(parser);
+ return null;
+ }
+ repositoryPath = path.normalize(arguments[0]);
+ repository = new GitRepository(repositoryPath);
+
+ analysisRoots = arguments
+ .sublist(1)
+ .map((String analysisRoot) => path.normalize(analysisRoot))
+ .toList();
+ for (String analysisRoot in analysisRoots) {
+ if (repositoryPath != analysisRoot &&
+ !path.isWithin(repositoryPath, analysisRoot)) {
+ _showUsage(parser,
+ 'Analysis roots must be contained within the repository: $analysisRoot');
+ return null;
+ }
+ }
+ //
+ // Replay the commit history.
+ //
+ Stopwatch stopwatch = new Stopwatch();
+ statistics.stopwatch = stopwatch;
+ stopwatch.start();
+ await server.start();
+ server.sendServerSetSubscriptions([ServerService.STATUS]);
+ server.sendAnalysisSetGeneralSubscriptions(
+ [GeneralAnalysisService.ANALYZED_FILES]);
+ // TODO(brianwilkerson) Get the list of glob patterns from the server after
+ // an API for getting them has been implemented.
+ fileGlobs = <Glob>[
+ new Glob(path.context.separator, '**.dart'),
+ new Glob(path.context.separator, '**.html'),
+ new Glob(path.context.separator, '**.htm'),
+ new Glob(path.context.separator, '**/.analysisOptions')
+ ];
+ try {
+ _replayChanges();
+ } finally {
+ server.sendServerShutdown();
+ repository.checkout('master');
+ }
+ stopwatch.stop();
+ //
+ // Print out statistics gathered while performing the simulation.
+ //
+ statistics.print();
+ return null;
+ }
+
+ /**
+ * Create and return a parser that can be used to parse the command-line
+ * arguments.
+ */
+ ArgParser _createArgParser() {
+ ArgParser parser = new ArgParser();
+ parser.addFlag(HELP_FLAG_NAME,
+ abbr: 'h',
+ help: 'Print usage information',
+ defaultsTo: false,
+ negatable: false);
+ return parser;
+ }
+
+ void _createSourceEdits(FileEdit fileEdit, BlobDiff blobDiff) {
+ LineInfo info = fileEdit.lineInfo;
+ for (DiffHunk hunk in blobDiff.hunks) {
+ List<SourceEdit> sourceEdits = <SourceEdit>[];
+ int srcStart = info.getOffsetOfLine(hunk.srcLine);
+ int srcEnd = info.getOffsetOfLine(hunk.srcLine + hunk.removeLines.length);
+ // TODO(brianwilkerson) Create multiple edits instead of a single edit.
+ sourceEdits.add(new SourceEdit(
+ srcStart, srcEnd - srcStart + 1, _join(hunk.addLines)));
+ fileEdit.addSourceEdits(sourceEdits);
+ }
+ }
+
+ /**
+ * Return athe absolute paths of all of the pubspec files in all of the
+ * analysis roots.
+ */
+ Iterable<String> _findPubspecsInAnalysisRoots() {
+ List<String> pubspecFiles = <String>[];
+ for (String directoryPath in analysisRoots) {
+ Directory directory = new Directory(directoryPath);
+ List<FileSystemEntity> children =
+ directory.listSync(recursive: true, followLinks: false);
+ for (FileSystemEntity child in children) {
+ String filePath = child.path;
+ if (path.basename(filePath) == PUBSPEC_FILE_NAME) {
+ pubspecFiles.add(filePath);
+ }
+ }
+ }
+ return pubspecFiles;
+ }
+
+ String _join(List<String> lines) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < lines.length; i++) {
+ buffer.writeln(lines[i]);
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Replay the changes in each commit.
+ */
+ void _replayChanges() {
+ //
+ // Get the revision history of the repo.
+ //
+ LinearCommitHistory history = repository.getCommitHistory();
+ statistics.commitCount = history.commitIds.length;
+ LinearCommitHistoryIterator iterator = history.iterator();
+ //
+ // Iterate over the history, applying changes.
+ //
+ bool firstCheckout = true;
+// Map<String, List<AnalysisError>> expectedErrors = null;
+ Iterable<String> changedPubspecs;
+ while (iterator.moveNext()) {
+ //
+ // Checkout the commit on which the changes are based.
+ //
+ repository.checkout(iterator.srcCommit);
+// if (expectedErrors != null) {
+// await server.analysisFinished;
+// server.expectErrorState(expectedErrors);
+// }
+ if (firstCheckout) {
+ changedPubspecs = _findPubspecsInAnalysisRoots();
+ server.sendAnalysisSetAnalysisRoots(analysisRoots, []);
+ firstCheckout = false;
+ } else {
+ server.removeAllOverlays();
+ }
+// await server.analysisFinished;
+// expectedErrors = server.errorMap;
+ for (String filePath in changedPubspecs) {
+ _runPub(filePath);
+ }
+ //
+ // Apply the changes.
+ //
+ CommitDelta commitDelta = iterator.next();
+ commitDelta.filterDiffs(analysisRoots, fileGlobs);
+ if (commitDelta.hasDiffs) {
+ statistics.commitsWithChangeInRootCount++;
+ _replayDiff(commitDelta);
+ }
+ changedPubspecs = commitDelta.filesMatching(PUBSPEC_FILE_NAME);
+ }
+ server.removeAllOverlays();
+ }
+
+ void _replayDiff(CommitDelta commitDelta) {
+ List<FileEdit> editList = <FileEdit>[];
+ for (DiffRecord record in commitDelta.diffRecords) {
+ FileEdit edit = new FileEdit(record);
+ _createSourceEdits(edit, record.getBlobDiff());
+ editList.add(edit);
+ }
+ // TODO(brianwilkerson) Randomize.
+ // Randomly select operations from different files to simulate a user
+ // editing multiple files simultaneously.
+ for (FileEdit edit in editList) {
+ List<String> currentFile = <String>[edit.filePath];
+ server.sendAnalysisSetPriorityFiles(currentFile);
+ server.sendAnalysisSetSubscriptions({
+ AnalysisService.FOLDING: currentFile,
+ AnalysisService.HIGHLIGHTS: currentFile,
+ AnalysisService.IMPLEMENTED: currentFile,
+ AnalysisService.NAVIGATION: currentFile,
+ AnalysisService.OCCURRENCES: currentFile,
+ AnalysisService.OUTLINE: currentFile,
+ AnalysisService.OVERRIDES: currentFile
+ });
+ for (ServerOperation operation in edit.getOperations()) {
+ operation.perform(server);
+ }
+ }
+ }
+
+ /**
+ * Run `pub` on the pubspec with the given [filePath].
+ */
+ void _runPub(String filePath) {
+ String directoryPath = path.dirname(filePath);
+ if (new Directory(directoryPath).existsSync()) {
+ Process.runSync(
+ '/Users/brianwilkerson/Dev/dart/dart-sdk/bin/pub', ['get'],
+ workingDirectory: directoryPath);
+ }
+ }
+
+ /**
+ * Display usage information, preceeded by the [errorMessage] if one is given.
+ */
+ void _showUsage(ArgParser parser, [String errorMessage = null]) {
+ if (errorMessage != null) {
+ stderr.writeln(errorMessage);
+ stderr.writeln();
+ }
+ stderr.writeln('''
+Usage: replay [options...] repositoryPath analysisRoot...
+
+Uses the commit history of the git repository at the given repository path to
+simulate the development of a code base while using the analysis server to
+analyze the code base.
+
+The repository path must be the absolute path of a directory containing a git
+repository.
+
+There must be at least one analysis root, and all of the analysis roots must be
+the absolute path of a directory contained within the repository directory. The
+analysis roots represent the portion of the repository that will be analyzed by
+the analysis server.
+
+OPTIONS:''');
+ stderr.writeln(parser.usage);
+ }
+}
+
+/**
+ * A representation of the edits to be applied to a single file.
+ */
+class FileEdit {
+ /**
+ * The absolute path of the file to be edited.
+ */
+ String filePath;
+
+ /**
+ * The content of the file before any edits have been applied.
+ */
+ String content;
+
+ /**
+ * The line info for the file before any edits have been applied.
+ */
+ LineInfo lineInfo;
+
+ /**
+ * The lists of source edits, one list for each hunk being edited.
+ */
+ List<List<SourceEdit>> editLists = <List<SourceEdit>>[];
+
+ /**
+ * Initialize a collection of edits to be associated with the file at the
+ * given [filePath].
+ */
+ FileEdit(DiffRecord record) {
+ filePath = record.srcPath;
+ if (record.isAddition) {
+ content = '';
+ lineInfo = new LineInfo(<int>[0]);
+ } else if (record.isCopy || record.isRename || record.isTypeChange) {
+ throw new ArgumentError('Unhandled change of type ${record.status}');
+ } else {
+ content = new File(filePath).readAsStringSync();
+ lineInfo = new LineInfo(StringUtilities.computeLineStarts(content));
+ }
+ }
+
+ /**
+ * Add a list of source edits that, taken together, transform a single hunk in
+ * the file.
+ */
+ void addSourceEdits(List<SourceEdit> sourceEdits) {
+ editLists.add(sourceEdits);
+ }
+
+ /**
+ * Return a list of operations to be sent to the server.
+ */
+ List<ServerOperation> getOperations() {
+ // TODO(brianwilkerson) Randomize.
+ // Make the order of edits random. Doing so will require updating the
+ // offsets of edits after the selected edit point.
+ List<ServerOperation> operations = <ServerOperation>[];
+ operations.add(
+ new AnalysisUpdateContent(filePath, new AddContentOverlay(content)));
+ for (List<SourceEdit> editList in editLists.reversed) {
+ for (SourceEdit edit in editList.reversed) {
+ operations.add(new AnalysisUpdateContent(
+ filePath, new ChangeContentOverlay([edit])));
+ }
+ }
+ operations
+ .add(new AnalysisUpdateContent(filePath, new RemoveContentOverlay()));
+ return operations;
+ }
+}
+
+/**
+ * A set of statistics related to the execution of the simulation.
+ */
+class Statistics {
+ /**
+ * The driver driving the simulation.
+ */
+ final Driver driver;
+
+ /**
+ * The stopwatch being used to time the simulation.
+ */
+ Stopwatch stopwatch;
+
+ /**
+ * The total number of commits in the repository.
+ */
+ int commitCount;
+
+ /**
+ * The number of commits in the repository that touched one of the files in
+ * one of the analysis roots.
+ */
+ int commitsWithChangeInRootCount = 0;
+
+ /**
+ * Initialize a newly created set of statistics.
+ */
+ Statistics(this.driver);
+
+ void print() {
+ stdout.write('Replay commits in ');
+ stdout.writeln(driver.repositoryPath);
+ stdout.write(' replay took ');
+ stdout.writeln(_printTime(stopwatch.elapsedMilliseconds));
+ stdout.write(' analysis roots = ');
+ stdout.writeln(driver.analysisRoots);
+ stdout.write(' number of commits = ');
+ stdout.writeln(commitCount);
+ stdout.write(' number of commits with a change in an analysis root = ');
+ stdout.writeln(commitsWithChangeInRootCount);
+ }
+
+ String _printTime(int milliseconds) {
+ int seconds = milliseconds ~/ 1000;
+ milliseconds -= seconds * 1000;
+ int minutes = seconds ~/ 60;
+ seconds -= minutes * 60;
+ int hours = minutes ~/ 60;
+ minutes -= hours * 60;
+
+ if (hours > 0) {
+ return '$hours:$minutes:$seconds.$milliseconds';
+ } else if (minutes > 0) {
+ return '$minutes:$seconds.$milliseconds m';
+ } else if (seconds > 0) {
+ return '$seconds.$milliseconds s';
+ }
+ return '$milliseconds ms';
+ }
+}
diff --git a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
index 43a520f..e465571 100644
--- a/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
+++ b/pkg/analysis_server/tool/spec/generated/java/AnalysisServer.java
@@ -119,6 +119,20 @@
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}
*
* Force the re-analysis of everything contained in the specified analysis roots. This will cause
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java b/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
index ab4020c..af83c5e 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ContextData.java
@@ -64,6 +64,11 @@
private final int workItemQueueLength;
/**
+ * A rolling average of work items in the queue. (A double encoded as a String.)
+ */
+ private final String workItemQueueLengthAverage;
+
+ /**
* Exceptions associated with cache entries.
*/
private final List<String> cacheEntryExceptions;
@@ -71,11 +76,12 @@
/**
* Constructor for {@link ContextData}.
*/
- public ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, List<String> cacheEntryExceptions) {
+ public ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, String workItemQueueLengthAverage, List<String> cacheEntryExceptions) {
this.name = name;
this.explicitFileCount = explicitFileCount;
this.implicitFileCount = implicitFileCount;
this.workItemQueueLength = workItemQueueLength;
+ this.workItemQueueLengthAverage = workItemQueueLengthAverage;
this.cacheEntryExceptions = cacheEntryExceptions;
}
@@ -88,6 +94,7 @@
other.explicitFileCount == explicitFileCount &&
other.implicitFileCount == implicitFileCount &&
other.workItemQueueLength == workItemQueueLength &&
+ ObjectUtilities.equals(other.workItemQueueLengthAverage, workItemQueueLengthAverage) &&
ObjectUtilities.equals(other.cacheEntryExceptions, cacheEntryExceptions);
}
return false;
@@ -98,8 +105,9 @@
int explicitFileCount = jsonObject.get("explicitFileCount").getAsInt();
int implicitFileCount = jsonObject.get("implicitFileCount").getAsInt();
int workItemQueueLength = jsonObject.get("workItemQueueLength").getAsInt();
+ String workItemQueueLengthAverage = jsonObject.get("workItemQueueLengthAverage").getAsString();
List<String> cacheEntryExceptions = JsonUtilities.decodeStringList(jsonObject.get("cacheEntryExceptions").getAsJsonArray());
- return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, cacheEntryExceptions);
+ return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, workItemQueueLengthAverage, cacheEntryExceptions);
}
public static List<ContextData> fromJsonArray(JsonArray jsonArray) {
@@ -149,6 +157,13 @@
return workItemQueueLength;
}
+ /**
+ * A rolling average of work items in the queue. (A double encoded as a String.)
+ */
+ public String getWorkItemQueueLengthAverage() {
+ return workItemQueueLengthAverage;
+ }
+
@Override
public int hashCode() {
HashCodeBuilder builder = new HashCodeBuilder();
@@ -156,6 +171,7 @@
builder.append(explicitFileCount);
builder.append(implicitFileCount);
builder.append(workItemQueueLength);
+ builder.append(workItemQueueLengthAverage);
builder.append(cacheEntryExceptions);
return builder.toHashCode();
}
@@ -166,6 +182,7 @@
jsonObject.addProperty("explicitFileCount", explicitFileCount);
jsonObject.addProperty("implicitFileCount", implicitFileCount);
jsonObject.addProperty("workItemQueueLength", workItemQueueLength);
+ jsonObject.addProperty("workItemQueueLengthAverage", workItemQueueLengthAverage);
JsonArray jsonArrayCacheEntryExceptions = new JsonArray();
for (String elt : cacheEntryExceptions) {
jsonArrayCacheEntryExceptions.add(new JsonPrimitive(elt));
@@ -186,6 +203,8 @@
builder.append(implicitFileCount + ", ");
builder.append("workItemQueueLength=");
builder.append(workItemQueueLength + ", ");
+ builder.append("workItemQueueLengthAverage=");
+ builder.append(workItemQueueLengthAverage + ", ");
builder.append("cacheEntryExceptions=");
builder.append(StringUtils.join(cacheEntryExceptions, ", "));
builder.append("]");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
index b8ba4c0..a5e439f 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/RequestErrorCode.java
@@ -59,6 +59,12 @@
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.
*/
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index d519a21..fcddc94 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -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
@@ -2489,6 +2525,12 @@
The number of work items in the queue.
</p>
</field>
+ <field name="workItemQueueLengthAverage">
+ <ref>String</ref>
+ <p>
+ A rolling average of work items in the queue. (A double encoded as a String.)
+ </p>
+ </field>
<field name="cacheEntryExceptions">
<list><ref>String</ref></list>
<p>
@@ -3644,6 +3686,14 @@
</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>
A path passed as an argument to a request (such as
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index d0af2b9..6ff682d 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 0.26.3
+* (Internal) Support for `_embedder.yaml` discovery and processing.
+
## 0.26.2
* Add code generation utilities for use in both analyzer and analysis server.
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 21e8d05..cbe175f 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -14,7 +14,7 @@
/**
* [File]s are leaf [Resource]s which contain data.
*/
-abstract class File extends Resource {
+abstract class File implements Resource {
/**
* Watch for changes to this file
*/
@@ -53,7 +53,7 @@
/**
* [Folder]s are [Resource]s which may contain files and/or other folders.
*/
-abstract class Folder extends Resource {
+abstract class Folder implements Resource {
/**
* Watch for changes to the files inside this folder (and in any nested
* folders, including folders reachable via links).
diff --git a/pkg/analyzer/lib/source/pub_package_map_provider.dart b/pkg/analyzer/lib/source/pub_package_map_provider.dart
index 07fdba7..5daf61d 100644
--- a/pkg/analyzer/lib/source/pub_package_map_provider.dart
+++ b/pkg/analyzer/lib/source/pub_package_map_provider.dart
@@ -59,6 +59,13 @@
@override
PackageMapInfo computePackageMap(Folder folder) {
+ // If the pubspec.lock file does not exist, no need to run anything.
+ {
+ String lockPath = getPubspecLockPath(folder);
+ if (!resourceProvider.getFile(lockPath).exists) {
+ return computePackageMapError(folder);
+ }
+ }
// TODO(paulberry) make this asynchronous so that we can (a) do other
// analysis while it's in progress, and (b) time out if it takes too long
// to respond.
@@ -96,13 +103,18 @@
// we'll know when to try running "pub list-package-dirs" again.
// Unfortunately, "pub list-package-dirs" doesn't tell us dependencies when
// an error occurs, so just assume there is one dependency, "pubspec.lock".
- List<String> dependencies = <String>[
- resourceProvider.pathContext.join(folder.path, PUBSPEC_LOCK_NAME)
- ];
+ String lockPath = getPubspecLockPath(folder);
+ List<String> dependencies = <String>[lockPath];
return new PackageMapInfo(null, dependencies.toSet());
}
/**
+ * Return the path to the `pubspec.lock` file in the given [folder].
+ */
+ String getPubspecLockPath(Folder folder) =>
+ resourceProvider.pathContext.join(folder.path, PUBSPEC_LOCK_NAME);
+
+ /**
* Decode the JSON output from pub into a package map. Paths in the
* output are considered relative to [folder].
*/
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index a609421..2b81cdd 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -66,7 +66,7 @@
*/
Iterable<Source> get sources {
return _partitions
- .map((CachePartition partition) => partition._sources)
+ .map((CachePartition partition) => partition.sources)
.expand((Iterable<Source> sources) => sources);
}
@@ -191,7 +191,7 @@
<Map<AnalysisTarget, CacheEntry>>[];
for (CachePartition partition in _partitions) {
if (context == null || partition.context == context) {
- maps.add(partition.map);
+ maps.add(partition.entryMap);
}
}
return new MultipleMapIterator<AnalysisTarget, CacheEntry>(maps);
@@ -495,7 +495,7 @@
// }
// valueStr = valueStr.replaceAll('\n', '\\n');
// print(
-// 'setValue $descriptor for $target value=$valueStr deps=$dependedOn');
+// 'setValue $descriptor for $target value=$valueStr $dependedOn=$dependedOn');
// }
_validateStateChange(descriptor, CacheState.VALID);
TargetedResult thisResult = new TargetedResult(target, descriptor);
@@ -509,14 +509,16 @@
}
/**
- * Set the value of the result represented by the given [descriptor] to the
- * given [value], keep its dependency, invalidate all the dependent result.
+ * If the result represented by the given [descriptor] is valid, set
+ * it to the given [value], keep its dependency, and if [invalidateDependent]
+ * invalidate all the dependent result.
*/
void setValueIncremental(
ResultDescriptor descriptor, dynamic value, bool invalidateDependent) {
ResultData data = getResultData(descriptor);
- data.state = CacheState.VALID;
- data.value = value;
+ if (data.state == CacheState.VALID || data.state == CacheState.FLUSHED) {
+ data.value = value;
+ }
if (invalidateDependent) {
_invalidateDependentResults(nextInvalidateId++, data, null, 0);
}
@@ -583,7 +585,7 @@
_invalidateDependentResults(id, thisData, delta, level + 1);
// If empty and not explicitly added, remove the entry altogether.
if (_resultMap.isEmpty && !explicitlyAdded) {
- _partition._targetMap.remove(target);
+ _partition.entryMap.remove(target);
_partition._removeIfSource(target);
}
// Notify controller.
@@ -856,18 +858,18 @@
* A table mapping the targets belonging to this partition to the information
* known about those targets.
*/
- HashMap<AnalysisTarget, CacheEntry> _targetMap =
+ final HashMap<AnalysisTarget, CacheEntry> entryMap =
new HashMap<AnalysisTarget, CacheEntry>();
/**
* A set of the [Source] targets.
*/
- final HashSet<Source> _sources = new HashSet<Source>();
+ final HashSet<Source> sources = new HashSet<Source>();
/**
* A table mapping full paths to lists of [Source]s with these full paths.
*/
- final Map<String, List<Source>> _pathToSources = <String, List<Source>>{};
+ final Map<String, List<Source>> pathToSource = <String, List<Source>>{};
/**
* Initialize a newly created cache partition, belonging to the given
@@ -876,35 +878,28 @@
CachePartition(this.context);
/**
- * Return a table mapping the targets known to the context to the information
- * known about the target.
- *
- * <b>Note:</b> This method is only visible for use by [AnalysisCache] and
- * should not be used for any other purpose.
- */
- Map<AnalysisTarget, CacheEntry> get map => _targetMap;
-
- /**
* Notifies the partition that the client is going to stop using it.
*/
void dispose() {
- for (CacheEntry entry in _targetMap.values) {
+ for (CacheEntry entry in entryMap.values) {
entry.dispose();
}
- _targetMap.clear();
+ entryMap.clear();
+ sources.clear();
+ pathToSource.clear();
}
/**
* Return the entry associated with the given [target].
*/
- CacheEntry get(AnalysisTarget target) => _targetMap[target];
+ CacheEntry get(AnalysisTarget target) => entryMap[target];
/**
* Return [Source]s whose full path is equal to the given [path].
* Maybe empty, but not `null`.
*/
List<Source> getSourcesWithFullName(String path) {
- List<Source> sources = _pathToSources[path];
+ List<Source> sources = pathToSource[path];
return sources != null ? sources : Source.EMPTY_LIST;
}
@@ -918,7 +913,7 @@
* cache entries.
*/
MapIterator<AnalysisTarget, CacheEntry> iterator() =>
- new SingleMapIterator<AnalysisTarget, CacheEntry>(_targetMap);
+ new SingleMapIterator<AnalysisTarget, CacheEntry>(entryMap);
/**
* Puts the given [entry] into the partition.
@@ -931,7 +926,7 @@
}
entry._partition = this;
entry.fixExceptionState();
- _targetMap[target] = entry;
+ entryMap[target] = entry;
_addIfSource(target);
}
@@ -944,7 +939,7 @@
for (CacheFlushManager flushManager in _flushManagerMap.values) {
flushManager.targetRemoved(target);
}
- CacheEntry entry = _targetMap.remove(target);
+ CacheEntry entry = entryMap.remove(target);
if (entry != null) {
entry._invalidateAll();
}
@@ -983,16 +978,16 @@
/**
* Return the number of targets that are mapped to cache entries.
*/
- int size() => _targetMap.length;
+ int size() => entryMap.length;
/**
- * If the given [target] is a [Source], adds it to [_sources].
+ * If the given [target] is a [Source], adds it to [sources].
*/
void _addIfSource(AnalysisTarget target) {
if (target is Source) {
- _sources.add(target);
+ sources.add(target);
String fullName = target.fullName;
- _pathToSources.putIfAbsent(fullName, () => <Source>[]).add(target);
+ pathToSource.putIfAbsent(fullName, () => <Source>[]).add(target);
}
}
@@ -1022,17 +1017,17 @@
}
/**
- * If the given [target] is a [Source], remove it from the list of [_sources].
+ * If the given [target] is a [Source], remove it from the list of [sources].
*/
void _removeIfSource(AnalysisTarget target) {
if (target is Source) {
- _sources.remove(target);
- String fullName = target.fullName;
- List<Source> sources = _pathToSources[fullName];
- if (sources != null) {
- sources.remove(target);
- if (sources.isEmpty) {
- _pathToSources.remove(fullName);
+ sources.remove(target);
+ String path = target.fullName;
+ List<Source> pathSources = pathToSource[path];
+ if (pathSources != null) {
+ pathSources.remove(target);
+ if (pathSources.isEmpty) {
+ pathToSource.remove(path);
}
}
}
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 9b2fa81..4d3651b 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -256,9 +256,6 @@
AnalysisOptions get analysisOptions => _options;
@override
- EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
-
- @override
void set analysisOptions(AnalysisOptions options) {
bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
options.analyzeFunctionBodiesPredicate ||
@@ -270,6 +267,9 @@
(this._options.lint && !options.lint) ||
this._options.preserveComments != options.preserveComments ||
this._options.strongMode != options.strongMode ||
+ ((options is AnalysisOptionsImpl)
+ ? this._options.strongModeHints != options.strongModeHints
+ : false) ||
this._options.enableStrictCallChecks !=
options.enableStrictCallChecks ||
this._options.enableGenericMethods != options.enableGenericMethods ||
@@ -293,6 +293,9 @@
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();
@@ -329,6 +332,9 @@
DeclaredVariables get declaredVariables => _declaredVariables;
@override
+ EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
+
+ @override
List<AnalysisTarget> get explicitTargets {
List<AnalysisTarget> targets = <AnalysisTarget>[];
MapIterator<AnalysisTarget, CacheEntry> iterator = _cache.iterator();
@@ -1155,6 +1161,8 @@
setValue(LIBRARY_ELEMENT3, library);
setValue(LIBRARY_ELEMENT4, library);
setValue(LIBRARY_ELEMENT5, library);
+ setValue(LIBRARY_ELEMENT6, library);
+ setValue(LIBRARY_ELEMENT7, library);
setValue(LINE_INFO, new LineInfo(<int>[0]));
setValue(PARSE_ERRORS, AnalysisError.NO_ERRORS);
entry.setState(PARSED_UNIT, CacheState.FLUSHED);
@@ -1183,6 +1191,7 @@
entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
// USED_IMPORTED_ELEMENTS
// USED_LOCAL_ELEMENTS
setValue(STRONG_MODE_ERRORS, AnalysisError.NO_ERRORS);
@@ -1268,6 +1277,7 @@
entry.setState(RESOLVED_UNIT8, CacheState.FLUSHED);
entry.setState(RESOLVED_UNIT9, CacheState.FLUSHED);
entry.setState(RESOLVED_UNIT10, CacheState.FLUSHED);
+ entry.setState(RESOLVED_UNIT11, CacheState.FLUSHED);
entry.setState(RESOLVED_UNIT, CacheState.FLUSHED);
}
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index 03cb8f1..f04a15e 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -5855,6 +5855,7 @@
* > constructorInitializer ::=
* > [SuperConstructorInvocation]
* > | [ConstructorFieldInitializer]
+ * > | [RedirectingConstructorInvocation]
*/
abstract class ConstructorInitializer extends AstNode {}
@@ -12946,6 +12947,95 @@
}
/**
+ * An object used to locate the [AstNode] associated with a source range.
+ * More specifically, they will return the deepest [AstNode] which completely
+ * encompasses the specified range.
+ */
+class NodeLocator2 extends UnifyingAstVisitor<Object> {
+ /**
+ * The inclusive start offset of the range used to identify the node.
+ */
+ int _startOffset = 0;
+
+ /**
+ * The inclusive end offset of the range used to identify the node.
+ */
+ int _endOffset = 0;
+
+ /**
+ * The found node or `null` if there is no such node.
+ */
+ AstNode _foundNode;
+
+ /**
+ * Initialize a newly created locator to locate the deepest [AstNode] for
+ * which `node.offset <= [startOffset]` and `[endOffset] < node.end`.
+ *
+ * If [endOffset] is not provided, then it is considered the same as the
+ * given [startOffset].
+ */
+ NodeLocator2(int startOffset, [int endOffset])
+ : this._startOffset = startOffset,
+ this._endOffset = endOffset == null ? startOffset : endOffset;
+
+ /**
+ * Search within the given AST [node] and return the node that was found,
+ * or `null` if no node was found.
+ */
+ AstNode searchWithin(AstNode node) {
+ if (node == null) {
+ return null;
+ }
+ try {
+ node.accept(this);
+ } on NodeLocator_NodeFoundException {} catch (exception, stackTrace) {
+ AnalysisEngine.instance.logger.logInformation(
+ "Unable to locate element at offset ($_startOffset - $_endOffset)",
+ new CaughtException(exception, stackTrace));
+ return null;
+ }
+ return _foundNode;
+ }
+
+ @override
+ Object visitNode(AstNode node) {
+ Token beginToken = node.beginToken;
+ Token endToken = node.endToken;
+ // Don't include synthetic tokens.
+ while (endToken != beginToken) {
+ if (endToken.type == TokenType.EOF || !endToken.isSynthetic) {
+ break;
+ }
+ endToken = endToken.previous;
+ }
+ int end = endToken.end;
+ int start = node.offset;
+ if (end <= _startOffset) {
+ return null;
+ }
+ if (start > _endOffset) {
+ return null;
+ }
+ try {
+ node.visitChildren(this);
+ } on NodeLocator_NodeFoundException {
+ rethrow;
+ } catch (exception, stackTrace) {
+ // Ignore the exception and proceed in order to visit the rest of the
+ // structure.
+ AnalysisEngine.instance.logger.logInformation(
+ "Exception caught while traversing an AST structure.",
+ new CaughtException(exception, stackTrace));
+ }
+ if (start <= _startOffset && _endOffset < end) {
+ _foundNode = node;
+ throw new NodeLocator_NodeFoundException();
+ }
+ return null;
+ }
+}
+
+/**
* An exception used by [NodeLocator] to cancel visiting after a node has been
* found.
*/
diff --git a/pkg/analyzer/lib/src/generated/constant.dart b/pkg/analyzer/lib/src/generated/constant.dart
index 2412506..8638c84 100644
--- a/pkg/analyzer/lib/src/generated/constant.dart
+++ b/pkg/analyzer/lib/src/generated/constant.dart
@@ -704,6 +704,13 @@
field is ConstFieldElementImpl) {
validator.beforeGetFieldEvaluationResult(field);
EvaluationResultImpl evaluationResult = field.evaluationResult;
+ // It is possible that the evaluation result is null.
+ // This happens for example when we have duplicate fields.
+ // class Test {final x = 1; final x = 2; const Test();}
+ if (evaluationResult == null) {
+ continue;
+ }
+ // Match the value and the type.
DartType fieldType =
FieldMember.from(field, constructor.returnType).type;
DartObjectImpl fieldValue = evaluationResult.value;
@@ -713,7 +720,7 @@
node,
[fieldValue.type, field.name, fieldType]);
}
- fieldMap[field.name] = evaluationResult.value;
+ fieldMap[field.name] = fieldValue;
}
}
// Now evaluate the constructor declaration.
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 7793d0d..334f4e8 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -9,12 +9,11 @@
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/dart.dart';
-import 'package:analyzer/task/model.dart'
- show AnalysisTarget, ConstantEvaluationTarget;
+import 'package:analyzer/task/model.dart' show AnalysisTarget;
import 'ast.dart';
import 'constant.dart' show DartObject, EvaluationResultImpl;
-import 'engine.dart' show AnalysisContext, AnalysisEngine, AnalysisException;
+import 'engine.dart' show AnalysisContext, AnalysisEngine;
import 'html.dart' show XmlAttributeNode, XmlTagNode;
import 'java_core.dart';
import 'java_engine.dart';
@@ -4540,6 +4539,15 @@
*/
abstract class FunctionType implements ParameterizedType {
/**
+ * The type parameters of this generic function. For example `<T> T -> T`.
+ *
+ * These are distinct from the [typeParameters] list, which contains type
+ * parameters from surrounding contexts, and thus are free type variables from
+ * the perspective of this function type.
+ */
+ List<TypeParameterElement> get boundTypeParameters;
+
+ /**
* Return a map from the names of named parameters to the types of the named
* parameters of this type of function. The entries in the map will be
* iterated in the same order as the order in which the named parameters were
@@ -4577,6 +4585,12 @@
DartType get returnType;
/**
+ * Return the type resulting from instantiating (replacing) the given
+ * [argumentTypes] for this function's bound type parameters.
+ */
+ FunctionType instantiate(List<DartType> argumentTypes);
+
+ /**
* Return `true` if this type is a subtype of the given [type].
*
* A function type <i>(T<sub>1</sub>, …, T<sub>n</sub>) → T</i> is
@@ -4647,6 +4661,7 @@
* this type's parameters. This is fully equivalent to
* `substitute(argumentTypes, getTypeArguments())`.
*/
+ @deprecated // use instantiate
FunctionType substitute3(List<DartType> argumentTypes);
}
@@ -4844,7 +4859,17 @@
/**
* The list of [typeArguments].
*/
- List<DartType> _typeArguments = DartType.EMPTY_LIST;
+ List<DartType> _typeArguments;
+
+ /**
+ * The list of [typeParameters].
+ */
+ List<TypeParameterElement> _typeParameters;
+
+ /**
+ * The list of [boundTypeParameters].
+ */
+ List<TypeParameterElement> _boundTypeParameters;
/**
* The set of typedefs which should not be expanded when exploring this type,
@@ -4859,7 +4884,7 @@
*/
FunctionTypeImpl(ExecutableElement element,
[List<FunctionTypeAliasElement> prunedTypedefs])
- : this._(element, null, prunedTypedefs, null);
+ : this._(element, null, prunedTypedefs, null, null, null);
/**
* Initialize a newly created function type to be declared by the given
@@ -4882,29 +4907,51 @@
*/
FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
[List<FunctionTypeAliasElement> prunedTypedefs])
- : this._(element, element?.name, prunedTypedefs, null);
+ : this._(element, element?.name, prunedTypedefs, null, null, null);
/**
* Private constructor.
*/
- FunctionTypeImpl._(Element element, String name, this.prunedTypedefs,
- List<DartType> typeArguments)
+ FunctionTypeImpl._(
+ TypeParameterizedElement element,
+ String name,
+ this.prunedTypedefs,
+ List<DartType> typeArguments,
+ List<TypeParameterElement> typeParameters,
+ List<TypeParameterElement> boundTypeParameters)
: super(element, name) {
- if (typeArguments != null) {
- _typeArguments = typeArguments;
- } else {
- List<TypeParameterElement> typeParameters = this.typeParameters;
+ _boundTypeParameters = boundTypeParameters ??
+ element?.typeParameters ??
+ TypeParameterElement.EMPTY_LIST;
+
+ if (typeParameters == null) {
+ // Combine the generic type variables from all enclosing contexts, except
+ // for this generic function's type variables. Those variables are
+ // tracked in [boundTypeParameters].
+ typeParameters = <TypeParameterElement>[];
+ Element e = element?.enclosingElement;
+ while (e != null) {
+ if (e is TypeParameterizedElement) {
+ typeParameters.addAll((e as TypeParameterizedElement).typeParameters);
+ }
+ e = e.enclosingElement;
+ }
+ }
+ _typeParameters = typeParameters;
+
+ if (typeArguments == null) {
// TODO(jmesserly): reuse TypeParameterTypeImpl.getTypes once we can
// make it generic, which will allow it to return List<DartType> instead
// of List<TypeParameterType>.
if (typeParameters.isEmpty) {
- _typeArguments = DartType.EMPTY_LIST;
+ typeArguments = DartType.EMPTY_LIST;
} else {
- _typeArguments = new List<DartType>.from(
+ typeArguments = new List<DartType>.from(
typeParameters.map((t) => t.type),
growable: false);
}
}
+ _typeArguments = typeArguments;
}
/**
@@ -4932,6 +4979,9 @@
}
@override
+ List<TypeParameterElement> get boundTypeParameters => _boundTypeParameters;
+
+ @override
String get displayName {
String name = this.name;
if (name == null || name.length == 0) {
@@ -5163,18 +5213,7 @@
List<DartType> get typeArguments => _typeArguments;
@override
- List<TypeParameterElement> get typeParameters {
- // Combine the generic type arguments from all enclosing contexts.
- // For example, this could be a generic method in a class, or a local
- // function within another function.
- List<TypeParameterElement> typeParams = <TypeParameterElement>[];
- for (Element e = element; e != null; e = e.enclosingElement) {
- if (e is TypeParameterizedElement) {
- typeParams.addAll(e.typeParameters);
- }
- }
- return typeParams;
- }
+ List<TypeParameterElement> get typeParameters => _typeParameters;
@override
bool operator ==(Object object) {
@@ -5182,6 +5221,24 @@
return false;
}
FunctionTypeImpl otherType = object as FunctionTypeImpl;
+ if (boundTypeParameters.length != otherType.boundTypeParameters.length) {
+ return false;
+ }
+ // `<T>T -> T` should be equal to `<U>U -> U`
+ // To test this, we instantiate both types with the same (unique) type
+ // variables, and see if the result is equal.
+ if (boundTypeParameters.isNotEmpty) {
+ List<DartType> instantiateTypeArgs = new List<DartType>();
+ for (TypeParameterElement e in boundTypeParameters) {
+ instantiateTypeArgs.add(new TypeParameterTypeImpl(
+ new TypeParameterElementImpl(e.name, -1)));
+ }
+ // After instantiation, they will no longer have boundTypeParameters,
+ // so we will continue below.
+ return this.instantiate(instantiateTypeArgs) ==
+ otherType.instantiate(instantiateTypeArgs);
+ }
+
return returnType == otherType.returnType &&
TypeImpl.equalArrays(
normalParameterTypes, otherType.normalParameterTypes) &&
@@ -5192,13 +5249,56 @@
@override
void appendTo(StringBuffer buffer) {
+ if (boundTypeParameters.isNotEmpty) {
+ // To print a type with type variables, first make sure we have unique
+ // variable names to print.
+ Set<TypeParameterType> freeVariables = new HashSet<TypeParameterType>();
+ _freeVariablesInFunctionType(this, freeVariables);
+
+ Set<String> namesToAvoid = new HashSet<String>();
+ for (DartType arg in freeVariables) {
+ if (arg is TypeParameterType) {
+ namesToAvoid.add(arg.displayName);
+ }
+ }
+
+ List<DartType> instantiateTypeArgs = new List<DartType>();
+ buffer.write("<");
+ for (TypeParameterElement e in boundTypeParameters) {
+ if (e != boundTypeParameters[0]) {
+ buffer.write(",");
+ }
+ String name = e.name;
+ int counter = 0;
+ while (!namesToAvoid.add(name)) {
+ // Unicode subscript-zero is U+2080, zero is U+0030. Other digits
+ // are sequential from there. Thus +0x2050 will get us the subscript.
+ String subscript = new String.fromCharCodes(
+ counter.toString().codeUnits.map((n) => n + 0x2050));
+
+ name = e.name + subscript;
+ counter++;
+ }
+ TypeParameterTypeImpl t =
+ new TypeParameterTypeImpl(new TypeParameterElementImpl(name, -1));
+ t.appendTo(buffer);
+ instantiateTypeArgs.add(t);
+ }
+ buffer.write(">");
+
+ // Instantiate it and print the resulting type. After instantiation, it
+ // will no longer have boundTypeParameters, so we will continue below.
+ this.instantiate(instantiateTypeArgs).appendTo(buffer);
+ return;
+ }
+
List<DartType> normalParameterTypes = this.normalParameterTypes;
List<DartType> optionalParameterTypes = this.optionalParameterTypes;
Map<String, DartType> namedParameterTypes = this.namedParameterTypes;
DartType returnType = this.returnType;
buffer.write("(");
bool needsComma = false;
- if (normalParameterTypes.length > 0) {
+ if (normalParameterTypes.isNotEmpty) {
for (DartType type in normalParameterTypes) {
if (needsComma) {
buffer.write(", ");
@@ -5208,7 +5308,7 @@
(type as TypeImpl).appendTo(buffer);
}
}
- if (optionalParameterTypes.length > 0) {
+ if (optionalParameterTypes.isNotEmpty) {
if (needsComma) {
buffer.write(", ");
needsComma = false;
@@ -5225,7 +5325,7 @@
buffer.write("]");
needsComma = true;
}
- if (namedParameterTypes.length > 0) {
+ if (namedParameterTypes.isNotEmpty) {
if (needsComma) {
buffer.write(", ");
needsComma = false;
@@ -5254,6 +5354,33 @@
}
@override
+ FunctionTypeImpl instantiate(List<DartType> argumentTypes) {
+ if (argumentTypes.length != boundTypeParameters.length) {
+ throw new IllegalArgumentException(
+ "argumentTypes.length (${argumentTypes.length}) != "
+ "boundTypeParameters.length (${boundTypeParameters.length})");
+ }
+ if (argumentTypes.isEmpty) {
+ return this;
+ }
+
+ // Given:
+ // {U/T} <S> T -> S
+ // Where {U/T} represents the typeArguments (U) and typeParameters (T) list,
+ // and <S> represents the boundTypeParameters.
+ //
+ // Now instantiate([V]), and the result should be:
+ // {U/T, V/S} T -> S.
+ List<TypeParameterElement> newTypeParams = typeParameters.toList();
+ List<DartType> newTypeArgs = typeArguments.toList();
+ newTypeParams.addAll(boundTypeParameters);
+ newTypeArgs.addAll(argumentTypes);
+
+ return new FunctionTypeImpl._(element, name, prunedTypedefs, newTypeArgs,
+ newTypeParams, TypeParameterElement.EMPTY_LIST);
+ }
+
+ @override
bool isAssignableTo(DartType type) {
// A function type T may be assigned to a function type S, written T <=> S,
// iff T <: S.
@@ -5502,7 +5629,8 @@
List<DartType> typeArgs = typeArguments
.map((TypeImpl t) => t.pruned(prune))
.toList(growable: false);
- return new FunctionTypeImpl._(element, name, prune, typeArgs);
+ return new FunctionTypeImpl._(element, name, prune, typeArgs,
+ _typeParameters, _boundTypeParameters);
}
}
@@ -5528,13 +5656,51 @@
}
List<DartType> typeArgs =
TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes);
- return new FunctionTypeImpl._(element, name, prune, typeArgs);
+ return new FunctionTypeImpl._(
+ element, name, prune, typeArgs, _typeParameters, _boundTypeParameters);
}
@override
FunctionTypeImpl substitute3(List<DartType> argumentTypes) =>
substitute2(argumentTypes, typeArguments);
+ void _freeVariablesInFunctionType(
+ FunctionType type, Set<TypeParameterType> free) {
+ // Make some fresh variables to avoid capture.
+ List<DartType> typeArgs = DartType.EMPTY_LIST;
+ if (type.boundTypeParameters.isNotEmpty) {
+ typeArgs = new List<DartType>.from(type.boundTypeParameters.map((e) =>
+ new TypeParameterTypeImpl(new TypeParameterElementImpl(e.name, -1))));
+
+ type = type.instantiate(typeArgs);
+ }
+
+ for (ParameterElement p in type.parameters) {
+ _freeVariablesInType(p.type, free);
+ }
+ _freeVariablesInType(type.returnType, free);
+
+ // Remove all of our bound variables.
+ free.removeAll(typeArgs);
+ }
+
+ void _freeVariablesInInterfaceType(
+ InterfaceType type, Set<TypeParameterType> free) {
+ for (DartType typeArg in type.typeArguments) {
+ _freeVariablesInType(typeArg, free);
+ }
+ }
+
+ void _freeVariablesInType(DartType type, Set<TypeParameterType> free) {
+ if (type is TypeParameterType) {
+ free.add(type);
+ } else if (type is FunctionType) {
+ _freeVariablesInFunctionType(type, free);
+ } else if (type is InterfaceType) {
+ _freeVariablesInInterfaceType(type, free);
+ }
+ }
+
/**
* Compute the least upper bound of types [f] and [g], both of which are
* known to be function types.
@@ -6356,6 +6522,12 @@
InterfaceType substitute2(
List<DartType> argumentTypes, List<DartType> parameterTypes);
+ // TODO(jmesserly): introduce a new "instantiate" and deprecate this.
+ // The new "instantiate" should work similar to FunctionType.instantiate,
+ // which uses [boundTypeParameters] to model type parameters that haven't been
+ // filled in yet. Those are kept separate from already-substituted type
+ // parameters or free variables from the enclosing scopes, which allows nested
+ // generics to work, such as a generic method in a generic class.
/**
* Return the type resulting from substituting the given arguments for this
* type's parameters. This is fully equivalent to `substitute2(argumentTypes,
@@ -7054,10 +7226,6 @@
InterfaceTypeImpl substitute2(
List<DartType> argumentTypes, List<DartType> parameterTypes,
[List<FunctionTypeAliasElement> prune]) {
- // Pruned types should only ever result from performing type variable
- // substitution, and it doesn't make sense to substitute again after
- // substituting once.
- assert(this.prunedTypedefs == null);
if (argumentTypes.length != parameterTypes.length) {
throw new IllegalArgumentException(
"argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})");
@@ -9284,6 +9452,9 @@
Element get enclosingElement => baseElement.enclosingElement;
@override
+ int get hashCode => baseElement.hashCode;
+
+ @override
bool get isInitializingFormal => baseElement.isInitializingFormal;
@override
@@ -9312,6 +9483,10 @@
SourceRange get visibleRange => baseElement.visibleRange;
@override
+ bool operator ==(Object object) =>
+ object is ParameterMember && baseElement == object.baseElement;
+
+ @override
accept(ElementVisitor visitor) => visitor.visitParameterElement(this);
@override
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index a715f9a..8c981ff 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -622,13 +622,17 @@
bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
ClassElementImpl typeReference = getTypeReference(target);
if (typeReference != null) {
- staticElement =
- propagatedElement = _resolveElement(typeReference, methodName);
+ staticElement = _resolveElement(typeReference, methodName);
} else {
staticElement = _resolveInvokedElementWithTarget(
target, staticType, methodName, isConditional);
- propagatedElement = _resolveInvokedElementWithTarget(
- target, propagatedType, methodName, isConditional);
+ // If we have propagated type information use it (since it should
+ // not be redundant with the staticType). Otherwise, don't produce
+ // a propagatedElement which duplicates the staticElement.
+ if (propagatedType is InterfaceType) {
+ propagatedElement = _resolveInvokedElementWithTarget(
+ target, propagatedType, methodName, isConditional);
+ }
}
}
staticElement = _convertSetterToGetter(staticElement);
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 597d381..fbb9825 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1160,9 +1160,6 @@
AnalysisOptions get analysisOptions => _options;
@override
- EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
-
- @override
void set analysisOptions(AnalysisOptions options) {
bool needsRecompute = this._options.analyzeFunctionBodiesPredicate !=
options.analyzeFunctionBodiesPredicate ||
@@ -1173,6 +1170,9 @@
(this._options.hint && !options.hint) ||
this._options.preserveComments != options.preserveComments ||
this._options.strongMode != options.strongMode ||
+ ((options is AnalysisOptionsImpl)
+ ? this._options.strongModeHints != options.strongModeHints
+ : false) ||
this._options.enableStrictCallChecks !=
options.enableStrictCallChecks ||
this._options.enableSuperMixins != options.enableSuperMixins;
@@ -1209,6 +1209,9 @@
this._options.lint = options.lint;
this._options.preserveComments = options.preserveComments;
this._options.strongMode = options.strongMode;
+ if (options is AnalysisOptionsImpl) {
+ this._options.strongModeHints = options.strongModeHints;
+ }
_generateImplicitErrors = options.generateImplicitErrors;
_generateSdkErrors = options.generateSdkErrors;
if (needsRecompute) {
@@ -1258,6 +1261,9 @@
DeclaredVariables get declaredVariables => _declaredVariables;
@override
+ EmbedderYamlLocator get embedderYamlLocator => _embedderYamlLocator;
+
+ @override
List<AnalysisTarget> get explicitTargets {
List<AnalysisTarget> targets = <AnalysisTarget>[];
MapIterator<Source, SourceEntry> iterator = _cache.iterator();
@@ -6462,6 +6468,14 @@
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
* values.
*/
@@ -6488,6 +6502,9 @@
lint = options.lint;
preserveComments = options.preserveComments;
strongMode = options.strongMode;
+ if (options is AnalysisOptionsImpl) {
+ strongModeHints = options.strongModeHints;
+ }
}
/**
@@ -6510,6 +6527,9 @@
lint = options.lint;
preserveComments = options.preserveComments;
strongMode = options.strongMode;
+ if (options is AnalysisOptionsImpl) {
+ strongModeHints = options.strongModeHints;
+ }
}
bool get analyzeFunctionBodies {
@@ -9420,6 +9440,9 @@
*/
set contentCache(ContentCache value);
+ /// Get the [EmbedderYamlLocator] for this context.
+ EmbedderYamlLocator get embedderYamlLocator;
+
/**
* Return a list of the explicit targets being analyzed by this context.
*/
@@ -9449,9 +9472,6 @@
*/
dynamic get privateAnalysisCachePartition;
- /// Get the [EmbedderYamlLocator] for this context.
- EmbedderYamlLocator get embedderYamlLocator;
-
/**
* A factory to override how [ResolverVisitor] is created.
*/
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index c15f247..1192f2c 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -904,12 +904,14 @@
isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) ||
isByTask(ComputeConstantValueTask.DESCRIPTOR) ||
isByTask(ComputeLibraryCycleTask.DESCRIPTOR) ||
+ isByTask(ComputePropagableVariableDependenciesTask.DESCRIPTOR) ||
isByTask(DartErrorsTask.DESCRIPTOR) ||
isByTask(ReadyLibraryElement2Task.DESCRIPTOR) ||
isByTask(ReadyLibraryElement5Task.DESCRIPTOR) ||
+ isByTask(ReadyLibraryElement6Task.DESCRIPTOR) ||
isByTask(ReadyResolvedUnitTask.DESCRIPTOR) ||
- isByTask(ReadyResolvedUnit9Task.DESCRIPTOR) ||
isByTask(ReadyResolvedUnit10Task.DESCRIPTOR) ||
+ isByTask(ReadyResolvedUnit11Task.DESCRIPTOR) ||
isByTask(EvaluateUnitConstantsTask.DESCRIPTOR) ||
isByTask(GenerateHintsTask.DESCRIPTOR) ||
isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
@@ -918,6 +920,10 @@
isByTask(LibraryUnitErrorsTask.DESCRIPTOR) ||
isByTask(ParseDartTask.DESCRIPTOR) ||
isByTask(PartiallyResolveUnitReferencesTask.DESCRIPTOR) ||
+ isByTask(PropagateVariableTypesInLibraryClosureTask.DESCRIPTOR) ||
+ isByTask(PropagateVariableTypesInLibraryTask.DESCRIPTOR) ||
+ isByTask(PropagateVariableTypesInUnitTask.DESCRIPTOR) ||
+ isByTask(PropagateVariableTypeTask.DESCRIPTOR) ||
isByTask(ScanDartTask.DESCRIPTOR) ||
isByTask(ResolveInstanceFieldsInUnitTask.DESCRIPTOR) ||
isByTask(ResolveLibraryReferencesTask.DESCRIPTOR) ||
diff --git a/pkg/analyzer/lib/src/generated/java_engine.dart b/pkg/analyzer/lib/src/generated/java_engine.dart
index 8b10e71..affcf8d 100644
--- a/pkg/analyzer/lib/src/generated/java_engine.dart
+++ b/pkg/analyzer/lib/src/generated/java_engine.dart
@@ -97,7 +97,9 @@
}
} else {
buffer.writeln(exception.toString());
- buffer.writeln(stackTrace.toString());
+ if (stackTrace != null) {
+ buffer.writeln(stackTrace.toString());
+ }
}
}
}
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 42872c1..2074525 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -5189,9 +5189,10 @@
_reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
return null;
} else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
+ TypeName returnType = _parseOptionalTypeNameComment();
_validateModifiersForTopLevelFunction(modifiers);
return _parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, null);
+ commentAndMetadata, modifiers.externalKeyword, returnType);
} else if (_peek()
.matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
if (modifiers.constKeyword == null &&
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index ad1cd60..0d17e72 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -6,6 +6,8 @@
import 'dart:collection';
+import '../task/strong/info.dart' show InferredType, StaticInfo;
+import '../task/strong/rules.dart' show TypeRules;
import 'ast.dart';
import 'constant.dart';
import 'element.dart';
@@ -2152,13 +2154,18 @@
_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);
@@ -5755,6 +5762,232 @@
}
/**
+ * Maintains and manages contextual type information used for
+ * inferring types.
+ */
+class InferenceContext {
+ // TODO(leafp): Consider replacing these node properties with a
+ // hash table help in an instance of this class.
+ static const String _typeProperty =
+ 'analyzer.src.generated.InferenceContext.contextType';
+
+ /**
+ * The error listener on which to record inference information.
+ */
+ final AnalysisErrorListener _errorListener;
+
+ /**
+ * If true, emit hints when types are inferred
+ */
+ final bool _inferenceHints;
+
+ /**
+ * Type provider, needed for type matching.
+ */
+ final TypeProvider _typeProvider;
+
+ /**
+ * The type system in use.
+ */
+ final TypeSystem _typeSystem;
+
+ /**
+ * The DDC type rules, used to create the inference info nodes.
+ */
+ final TypeRules _rules;
+
+ /**
+ * A stack of return types for all of the enclosing
+ * functions and methods.
+ */
+ List<DartType> _returnStack = <DartType>[];
+
+ InferenceContext._(this._errorListener, TypeProvider typeProvider,
+ this._typeSystem, this._inferenceHints)
+ : _typeProvider = typeProvider,
+ _rules = new TypeRules(typeProvider);
+
+ /**
+ * Get the return type of the current enclosing function, if any.
+ */
+ DartType get returnContext =>
+ (_returnStack.isNotEmpty) ? _returnStack.last : null;
+
+ /**
+ * Match type [t1] against type [t2] as follows.
+ * If `t1 = I<dynamic, ..., dynamic>`, then look for a supertype
+ * of t1 of the form `K<S0, ..., Sm>` where `t2 = K<S0', ..., Sm'>`
+ * If the supertype exists, use the constraints `S0 <: S0', ... Sm <: Sm'`
+ * to derive a concrete instantation for I of the form `<T0, ..., Tn>`,
+ * such that `I<T0, .., Tn> <: t2`
+ */
+ List<DartType> matchTypes(DartType t1, DartType t2) =>
+ (t1 is InterfaceType && t2 is InterfaceType) ? _matchTypes(t1, t2) : null;
+
+ /**
+ * Pop a return type off of the return stack.
+ */
+ void popReturnContext() {
+ assert(_returnStack.isNotEmpty);
+ if (_returnStack.isNotEmpty) {
+ _returnStack.removeLast();
+ }
+ }
+
+ /**
+ * Push a [returnType] onto the return stack.
+ */
+ void pushReturnContext(DartType returnType) {
+ _returnStack.add(returnType);
+ }
+
+ /**
+ * Place an info node into the error stream indicating that a
+ * [type] has been inferred as the type of [node].
+ */
+ void recordInference(Expression node, DartType type) {
+ StaticInfo info = InferredType.create(_rules, node, type);
+ if (!_inferenceHints || info == null) {
+ return;
+ }
+ AnalysisError error = info.toAnalysisError();
+ _errorListener.onError(error);
+ }
+
+ List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
+ if (t1 == t2) {
+ return t2.typeArguments;
+ }
+ List<DartType> tArgs1 = t1.typeArguments;
+ List<DartType> tArgs2 = t2.typeArguments;
+ // If t1 isn't a raw type, bail out
+ if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) {
+ return null;
+ }
+
+ // This is our inferred type argument list. We start at all dynamic,
+ // and fill in with inferred types when we reach a match.
+ List<DartType> actuals =
+ new List<DartType>.filled(tArgs1.length, _typeProvider.dynamicType);
+
+ // When we find the supertype of t1 with the same
+ // classname as t2 (see below), we have the following:
+ // If t1 is an instantiation of a class T1<X0, ..., Xn>
+ // and t2 is an instantiation of a class T2<Y0, ...., Ym>
+ // of the form t2 = T2<S0, ..., Sm>
+ // then we want to choose instantiations for the Xi
+ // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
+ // To find this, we simply instantate T1 with
+ // X0, ..., Xn, and then find its superclass
+ // T2<T0', ..., Tn'>. We then solve the constraint
+ // set T0' <: S0, ..., Tn' <: Sn for the Xi.
+ // Currently, we only handle constraints where
+ // the Ti' is one of the Xi'. If there are multiple
+ // constraints on some Xi, we choose the lower of the
+ // two (if it exists).
+ bool permute(List<DartType> permutedArgs) {
+ if (permutedArgs == null) {
+ return false;
+ }
+ List<TypeParameterElement> ps = t1.typeParameters;
+ List<DartType> ts = ps.map((p) => p.type).toList();
+ for (int i = 0; i < permutedArgs.length; i++) {
+ DartType tVar = permutedArgs[i];
+ DartType tActual = tArgs2[i];
+ int index = ts.indexOf(tVar);
+ if (index >= 0 && _typeSystem.isSubtypeOf(tActual, actuals[index])) {
+ actuals[index] = tActual;
+ }
+ }
+ return actuals.any((x) => !x.isDynamic);
+ }
+
+ // Look for the first supertype of t1 with the same class name as t2.
+ bool match(InterfaceType t1, Set<Element> visited) {
+ if (t1.element == t2.element) {
+ return permute(t1.typeArguments);
+ }
+
+ if (t1 == _typeProvider.objectType) {
+ return false;
+ }
+
+ Element element = t1.element;
+ if (visited == null) {
+ visited = new HashSet<Element>();
+ }
+ if (element == null || !visited.add(element)) {
+ return false;
+ }
+ try {
+ if (match(t1.superclass, visited)) {
+ return true;
+ }
+
+ for (final parent in t1.mixins) {
+ if (match(parent, visited)) {
+ return true;
+ }
+ }
+
+ for (final parent in t1.interfaces) {
+ if (match(parent, visited)) {
+ return true;
+ }
+ }
+ } finally {
+ visited.remove(element);
+ }
+ return false;
+ }
+
+ // We have that t1 = T1<dynamic, ..., dynamic>.
+ // To match t1 against t2, we use the uninstantiated version
+ // of t1, essentially treating it as an instantiation with
+ // fresh variables, and solve for the variables.
+ // t1.element.type will be of the form T1<X0, ..., Xn>
+ if (!match(t1.element.type, null)) {
+ return null;
+ }
+ DartType newT1 = t1.element.type.substitute4(actuals);
+ // If we found a solution, return it.
+ if (_typeSystem.isSubtypeOf(newT1, t2)) {
+ return actuals;
+ }
+ return null;
+ }
+
+ /**
+ * Clear the type information assocated with [node].
+ */
+ static void clearType(AstNode node) {
+ node?.setProperty(_typeProperty, null);
+ }
+
+ /**
+ * Look for contextual type information attached to [node]. Returns
+ * the type if found, otherwise null.
+ */
+ static DartType getType(AstNode node) => node?.getProperty(_typeProperty);
+
+ /**
+ * Attach contextual type information [type] to [node] for use during
+ * inference.
+ */
+ static void setType(AstNode node, DartType type) {
+ node?.setProperty(_typeProperty, type);
+ }
+
+ /**
+ * Attach contextual type information [type] to [node] for use during
+ * inference.
+ */
+ static void setTypeFromNode(AstNode innerNode, AstNode outerNode) {
+ setType(innerNode, getType(outerNode));
+ }
+}
+
+/**
* Instances of the class `InheritanceManager` manage the knowledge of where class members
* (methods, getters & setters) are inherited from.
*/
@@ -9725,18 +9958,18 @@
*/
class PartialResolverVisitor extends ResolverVisitor {
/**
- * A flag indicating whether the resolver is being run in strong mode.
- */
- final bool strongMode;
-
- /**
* The static variables and fields that have an initializer. These are the
* variables that need to be re-resolved after static variables have their
* types inferred. A subset of these variables are those whose types should
- * be inferred. The list will be empty unless the resolver is being run in
- * strong mode.
+ * be inferred.
*/
- final List<VariableElement> variablesAndFields = <VariableElement>[];
+ final List<VariableElement> staticVariables = <VariableElement>[];
+
+ /**
+ * The static and instance variables and fields that have an initializer.
+ * These are the variables whose types might be propagated.
+ */
+ final List<VariableElement> propagableVariables = <VariableElement>[];
/**
* Initialize a newly created visitor to resolve the nodes in an AST node.
@@ -9760,8 +9993,7 @@
{Scope nameScope,
InheritanceManager inheritanceManager,
StaticTypeAnalyzerFactory typeAnalyzerFactory})
- : strongMode = definingLibrary.context.analysisOptions.strongMode,
- super(definingLibrary, source, typeProvider, errorListener);
+ : super(definingLibrary, source, typeProvider, errorListener);
@override
Object visitBlockFunctionBody(BlockFunctionBody node) {
@@ -9781,8 +10013,9 @@
@override
Object visitFieldDeclaration(FieldDeclaration node) {
- if (strongMode && node.isStatic) {
- _addVariables(node.fields.variables);
+ _addPropagableVariables(node.fields.variables);
+ if (node.isStatic) {
+ _addStaticVariables(node.fields.variables);
}
return super.visitFieldDeclaration(node);
}
@@ -9794,23 +10027,36 @@
@override
Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
- if (strongMode) {
- _addVariables(node.variables.variables);
- }
+ _addPropagableVariables(node.variables.variables);
+ _addStaticVariables(node.variables.variables);
return super.visitTopLevelVariableDeclaration(node);
}
/**
+ * Add all of the [variables] with initializers to [propagableVariables].
+ */
+ void _addPropagableVariables(List<VariableDeclaration> variables) {
+ for (VariableDeclaration variable in variables) {
+ if (variable.initializer != null) {
+ VariableElement element = variable.element;
+ if (element.isConst || element.isFinal) {
+ propagableVariables.add(element);
+ }
+ }
+ }
+ }
+
+ /**
* Add all of the [variables] with initializers to the list of variables whose
* type can be inferred. Technically, we only infer the types of variables
* that do not have a static type, but all variables with initializers
* potentially need to be re-resolved after inference because they might
* refer to a field whose type was inferred.
*/
- void _addVariables(NodeList<VariableDeclaration> variables) {
+ void _addStaticVariables(List<VariableDeclaration> variables) {
for (VariableDeclaration variable in variables) {
if (variable.initializer != null) {
- variablesAndFields.add(variable.element);
+ staticVariables.add(variable.element);
}
}
}
@@ -10372,8 +10618,8 @@
StaticTypeAnalyzer typeAnalyzer;
/*
- * The type system in use during resolution.
- */
+ * The type system in use during resolution.
+ */
TypeSystem typeSystem;
/**
@@ -10406,6 +10652,8 @@
*/
Comment _commentBeforeFunction = null;
+ InferenceContext inferenceContext = null;
+
/**
* The object keeping track of which elements have had their types overridden.
*/
@@ -10457,6 +10705,13 @@
}
this.elementResolver = new ElementResolver(this);
this.typeSystem = definingLibrary.context.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 {
@@ -10729,11 +10984,65 @@
identical(parent, _enclosingFunctionTypeAlias)) {
return null;
}
- return super.visitAnnotation(node);
+ safelyVisit(node.name);
+ safelyVisit(node.constructorName);
+ Element element = node.element;
+ if (element is ExecutableElement) {
+ InferenceContext.setType(node.arguments, element.type);
+ }
+ safelyVisit(node.arguments);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
+ return null;
+ }
+
+ @override
+ Object visitArgumentList(ArgumentList node) {
+ DartType callerType = InferenceContext.getType(node);
+ if (callerType is FunctionType) {
+ Map<String, DartType> namedParameterTypes =
+ callerType.namedParameterTypes;
+ List<DartType> normalParameterTypes = callerType.normalParameterTypes;
+ List<DartType> optionalParameterTypes = callerType.optionalParameterTypes;
+ int normalCount = normalParameterTypes.length;
+ int optionalCount = optionalParameterTypes.length;
+
+ NodeList<Expression> arguments = node.arguments;
+ Iterable<Expression> positional =
+ arguments.takeWhile((l) => l is! NamedExpression);
+ Iterable<Expression> required = positional.take(normalCount);
+ Iterable<Expression> optional =
+ positional.skip(normalCount).take(optionalCount);
+ Iterable<Expression> named =
+ arguments.skipWhile((l) => l is! NamedExpression);
+
+ //TODO(leafp): Consider using the parameter elements here instead.
+ //TODO(leafp): Make sure that the parameter elements are getting
+ // setup correctly with inference.
+ int index = 0;
+ for (Expression argument in required) {
+ InferenceContext.setType(argument, normalParameterTypes[index++]);
+ }
+ index = 0;
+ for (Expression argument in optional) {
+ InferenceContext.setType(argument, optionalParameterTypes[index++]);
+ }
+
+ for (Expression argument in named) {
+ if (argument is NamedExpression) {
+ DartType type = namedParameterTypes[argument.name.label.name];
+ if (type != null) {
+ InferenceContext.setType(argument, type);
+ }
+ }
+ }
+ }
+ return super.visitArgumentList(node);
}
@override
Object visitAsExpression(AsExpression node) {
+ InferenceContext.setType(node.expression, node.type.type);
super.visitAsExpression(node);
// Since an as-statement doesn't actually change the type, we don't
// let it affect the propagated type when it would result in a loss
@@ -10750,6 +11059,33 @@
}
@override
+ Object visitAssignmentExpression(AssignmentExpression node) {
+ safelyVisit(node.leftHandSide);
+ sc.TokenType operator = node.operator.type;
+ if (operator == sc.TokenType.EQ ||
+ operator == sc.TokenType.QUESTION_QUESTION_EQ) {
+ InferenceContext.setType(
+ node.rightHandSide, node.leftHandSide.staticType);
+ }
+ safelyVisit(node.rightHandSide);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
+ return null;
+ }
+
+ @override
+ Object visitAwaitExpression(AwaitExpression node) {
+ //TODO(leafp): Handle the implicit union type here
+ DartType contextType = InferenceContext.getType(node);
+ if (contextType != null) {
+ InterfaceType futureT =
+ typeProvider.futureType.substitute4([contextType]);
+ InferenceContext.setType(node.expression, futureT);
+ }
+ return super.visitAwaitExpression(node);
+ }
+
+ @override
Object visitBinaryExpression(BinaryExpression node) {
sc.TokenType operatorType = node.operator.type;
Expression leftOperand = node.leftOperand;
@@ -10789,6 +11125,8 @@
}
}
} else {
+ // TODO(leafp): Do downwards inference using the declared type
+ // of the binary operator.
safelyVisit(leftOperand);
safelyVisit(rightOperand);
}
@@ -10802,9 +11140,11 @@
safelyVisit(_commentBeforeFunction);
_overrideManager.enterScope();
try {
+ inferenceContext.pushReturnContext(InferenceContext.getType(node));
super.visitBlockFunctionBody(node);
} finally {
_overrideManager.exitScope();
+ inferenceContext.popReturnContext();
}
return null;
}
@@ -10821,6 +11161,12 @@
}
@override
+ Object visitCascadeExpression(CascadeExpression node) {
+ InferenceContext.setTypeFromNode(node.target, node);
+ return super.visitCascadeExpression(node);
+ }
+
+ @override
Object visitClassDeclaration(ClassDeclaration node) {
//
// Resolve the metadata in the library scope.
@@ -10953,6 +11299,7 @@
_clearTypePromotionsIfAccessedInClosureAndProtentiallyMutated(
thenExpression);
// Visit "then" expression.
+ InferenceContext.setTypeFromNode(thenExpression, node);
thenExpression.accept(this);
} finally {
_promoteManager.exitScope();
@@ -10966,6 +11313,7 @@
_overrideManager.enterScope();
try {
_propagateFalseState(condition);
+ InferenceContext.setTypeFromNode(elseExpression, node);
elseExpression.accept(this);
} finally {
_overrideManager.exitScope();
@@ -10990,6 +11338,8 @@
ExecutableElement outerFunction = _enclosingFunction;
try {
_enclosingFunction = node.element;
+ FunctionType type = _enclosingFunction.type;
+ InferenceContext.setType(node.body, type.returnType);
super.visitConstructorDeclaration(node);
} finally {
_enclosingFunction = outerFunction;
@@ -11006,6 +11356,8 @@
// We visit the expression, but do not visit the field name because it needs
// to be visited in the context of the constructor field initializer node.
//
+ FieldElement fieldElement = enclosingClass.getField(node.fieldName.name);
+ InferenceContext.setType(node.expression, fieldElement?.type);
safelyVisit(node.expression);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -11037,6 +11389,7 @@
@override
Object visitDefaultFormalParameter(DefaultFormalParameter node) {
+ InferenceContext.setType(node.defaultValue, node.parameter.element?.type);
super.visitDefaultFormalParameter(node);
ParameterElement element = node.element;
if (element.initializer != null && node.defaultValue != null) {
@@ -11115,6 +11468,7 @@
}
_overrideManager.enterScope();
try {
+ InferenceContext.setTypeFromNode(node.expression, node);
super.visitExpressionFunctionBody(node);
} finally {
_overrideManager.exitScope();
@@ -11154,9 +11508,16 @@
// cannot be in scope while visiting the iterator.
//
Expression iterable = node.iterable;
- safelyVisit(iterable);
DeclaredIdentifier loopVariable = node.loopVariable;
SimpleIdentifier identifier = node.identifier;
+ if (loopVariable?.type?.type != null) {
+ InterfaceType targetType = (node.awaitKeyword == null)
+ ? typeProvider.iterableType
+ : typeProvider.streamType;
+ InferenceContext.setType(
+ iterable, targetType.substitute4([loopVariable.type.type]));
+ }
+ safelyVisit(iterable);
safelyVisit(loopVariable);
safelyVisit(identifier);
Statement body = node.body;
@@ -11229,6 +11590,8 @@
try {
SimpleIdentifier functionName = node.name;
_enclosingFunction = functionName.staticElement as ExecutableElement;
+ InferenceContext.setType(
+ node.functionExpression, _enclosingFunction.type);
super.visitFunctionDeclaration(node);
} finally {
_enclosingFunction = outerFunction;
@@ -11243,6 +11606,11 @@
_enclosingFunction = node.element;
_overrideManager.enterScope();
try {
+ DartType functionType = InferenceContext.getType(node);
+ if (functionType is FunctionType) {
+ _inferFormalParameterList(node.parameters, functionType);
+ InferenceContext.setType(node.body, functionType.returnType);
+ }
super.visitFunctionExpression(node);
} finally {
_overrideManager.exitScope();
@@ -11258,6 +11626,7 @@
safelyVisit(node.function);
node.accept(elementResolver);
_inferFunctionExpressionsParametersTypes(node.argumentList);
+ InferenceContext.setType(node.argumentList, node.function.staticType);
safelyVisit(node.argumentList);
node.accept(typeAnalyzer);
return null;
@@ -11345,16 +11714,99 @@
}
@override
+ Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ TypeName classTypeName = node.constructorName.type;
+ if (classTypeName.typeArguments == null) {
+ DartType contextType = InferenceContext.getType(node);
+ if (contextType is InterfaceType &&
+ contextType.typeArguments != null &&
+ contextType.typeArguments.length > 0) {
+ List<DartType> targs =
+ inferenceContext.matchTypes(classTypeName.type, contextType);
+ if (targs != null && targs.any((t) => !t.isDynamic)) {
+ ClassElement classElement = classTypeName.type.element;
+ InterfaceType rawType = classElement.type;
+ InterfaceType fullType =
+ rawType.substitute2(targs, rawType.typeArguments);
+ // The element resolver uses the type on the constructor name, so
+ // infer it first
+ typeAnalyzer.inferConstructorName(node.constructorName, fullType);
+ }
+ }
+ }
+ safelyVisit(node.constructorName);
+ FunctionType constructorType = node.constructorName.staticElement?.type;
+ if (constructorType != null) {
+ InferenceContext.setType(node.argumentList, constructorType);
+ }
+ safelyVisit(node.argumentList);
+ node.accept(elementResolver);
+ node.accept(typeAnalyzer);
+ return null;
+ }
+
+ @override
Object visitLabel(Label node) => null;
@override
Object visitLibraryIdentifier(LibraryIdentifier node) => null;
@override
+ Object visitListLiteral(ListLiteral node) {
+ DartType contextType = InferenceContext.getType(node);
+ if (node.typeArguments == null && contextType is InterfaceType) {
+ InterfaceType listD =
+ typeProvider.listType.substitute4([typeProvider.dynamicType]);
+ List<DartType> targs = inferenceContext.matchTypes(listD, contextType);
+ if (targs != null &&
+ targs.length == 1 &&
+ targs.any((t) => !t.isDynamic)) {
+ DartType eType = targs[0];
+ InterfaceType listT = typeProvider.listType.substitute4([eType]);
+ for (Expression child in node.elements) {
+ InferenceContext.setType(child, eType);
+ }
+ InferenceContext.setType(node, listT);
+ } else {
+ InferenceContext.clearType(node);
+ }
+ }
+ super.visitListLiteral(node);
+ return null;
+ }
+
+ @override
+ Object visitMapLiteral(MapLiteral node) {
+ DartType contextType = InferenceContext.getType(node);
+ if (node.typeArguments == null && contextType is InterfaceType) {
+ InterfaceType mapD = typeProvider.mapType
+ .substitute4([typeProvider.dynamicType, typeProvider.dynamicType]);
+ List<DartType> targs = inferenceContext.matchTypes(mapD, contextType);
+ if (targs != null &&
+ targs.length == 2 &&
+ targs.any((t) => !t.isDynamic)) {
+ DartType kType = targs[0];
+ DartType vType = targs[1];
+ InterfaceType mapT = typeProvider.mapType.substitute4([kType, vType]);
+ for (MapLiteralEntry entry in node.entries) {
+ InferenceContext.setType(entry.key, kType);
+ InferenceContext.setType(entry.value, vType);
+ }
+ InferenceContext.setType(node, mapT);
+ } else {
+ InferenceContext.clearType(node);
+ }
+ }
+ super.visitMapLiteral(node);
+ return null;
+ }
+
+ @override
Object visitMethodDeclaration(MethodDeclaration node) {
ExecutableElement outerFunction = _enclosingFunction;
try {
_enclosingFunction = node.element;
+ InferenceContext.setType(node.body, node.element.type?.returnType);
super.visitMethodDeclaration(node);
} finally {
_enclosingFunction = outerFunction;
@@ -11371,12 +11823,22 @@
safelyVisit(node.target);
node.accept(elementResolver);
_inferFunctionExpressionsParametersTypes(node.argumentList);
+ Element methodElement = node.methodName.staticElement;
+ if (methodElement is ExecutableElement) {
+ InferenceContext.setType(node.argumentList, methodElement.type);
+ }
safelyVisit(node.argumentList);
node.accept(typeAnalyzer);
return null;
}
@override
+ Object visitNamedExpression(NamedExpression node) {
+ InferenceContext.setType(node.expression, InferenceContext.getType(node));
+ return super.visitNamedExpression(node);
+ }
+
+ @override
Object visitNode(AstNode node) {
node.visitChildren(this);
node.accept(elementResolver);
@@ -11385,6 +11847,12 @@
}
@override
+ Object visitParenthesizedExpression(ParenthesizedExpression node) {
+ InferenceContext.setType(node.expression, InferenceContext.getType(node));
+ return super.visitParenthesizedExpression(node);
+ }
+
+ @override
Object visitPrefixedIdentifier(PrefixedIdentifier node) {
//
// We visit the prefix, but do not visit the identifier because it needs to
@@ -11416,6 +11884,7 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
+ InferenceContext.setType(node.argumentList, node.staticElement?.type);
safelyVisit(node.argumentList);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -11423,6 +11892,12 @@
}
@override
+ Object visitReturnStatement(ReturnStatement node) {
+ InferenceContext.setType(node.expression, inferenceContext.returnContext);
+ return super.visitReturnStatement(node);
+ }
+
+ @override
Object visitShowCombinator(ShowCombinator node) => null;
@override
@@ -11432,6 +11907,7 @@
// because it needs to be visited in the context of the constructor
// invocation.
//
+ InferenceContext.setType(node.argumentList, node.staticElement?.type);
safelyVisit(node.argumentList);
node.accept(elementResolver);
node.accept(typeAnalyzer);
@@ -11479,6 +11955,7 @@
@override
Object visitVariableDeclaration(VariableDeclaration node) {
+ InferenceContext.setType(node.initializer, InferenceContext.getType(node));
super.visitVariableDeclaration(node);
VariableElement element = node.element;
if (element.initializer != null && node.initializer != null) {
@@ -11500,6 +11977,13 @@
return null;
}
+ @override visitVariableDeclarationList(VariableDeclarationList node) {
+ for (VariableDeclaration decl in node.variables) {
+ InferenceContext.setType(decl, node.type?.type);
+ }
+ super.visitVariableDeclarationList(node);
+ }
+
@override
Object visitWhileStatement(WhileStatement node) {
// Note: since we don't call the base class, we have to maintain
@@ -11529,6 +12013,32 @@
return null;
}
+ @override
+ Object visitYieldStatement(YieldStatement node) {
+ DartType returnType = inferenceContext.returnContext;
+ if (returnType != null && _enclosingFunction != null) {
+ // If we're not in a generator ([a]sync*, then we shouldn't have a yield.
+ // so don't infer
+ if (_enclosingFunction.isGenerator) {
+ // If this is a yield*, then we just propagate the return type downwards
+ DartType type = returnType;
+ // If this just a yield, then we need to get the element type
+ if (node.star == null) {
+ // If it's synchronous, we expect Iterable<T>, otherwise Stream<T>
+ InterfaceType wrapperD = _enclosingFunction.isSynchronous
+ ? typeProvider.iterableDynamicType
+ : typeProvider.streamDynamicType;
+ // Match the types to instantiate the type arguments if possible
+ List<DartType> targs =
+ inferenceContext.matchTypes(wrapperD, returnType);
+ type = (targs?.length == 1) ? targs[0] : null;
+ }
+ InferenceContext.setType(node.expression, type);
+ }
+ }
+ return super.visitYieldStatement(node);
+ }
+
/**
* Checks each promoted variable in the current scope for compliance with the following
* specification statement:
@@ -11623,6 +12133,14 @@
return null;
}
+ void _inferFormalParameterList(FormalParameterList node, DartType type) {
+ if (typeAnalyzer.inferFormalParameterList(node, type)) {
+ // TODO(leafp): This gets dropped on the floor if we're in the field
+ // inference task. We should probably keep these infos.
+ inferenceContext.recordInference(node.parent, type);
+ }
+ }
+
/**
* If given "mayBeClosure" is [FunctionExpression] without explicit parameters types and its
* required type is [FunctionType], then infer parameters types from [FunctionType].
@@ -14439,7 +14957,7 @@
if (argumentList != null) {
NodeList<TypeName> arguments = argumentList.arguments;
int argumentCount = arguments.length;
- List<DartType> parameters = _getTypeArguments(type);
+ List<DartType> parameters = _getTypeParameters(type);
int parameterCount = parameters.length;
List<DartType> typeArguments = new List<DartType>(parameterCount);
if (argumentCount == parameterCount) {
@@ -14458,21 +14976,13 @@
typeArguments[i] = _dynamicType;
}
}
- if (type is InterfaceTypeImpl) {
- InterfaceTypeImpl interfaceType = type as InterfaceTypeImpl;
- type = interfaceType.substitute4(typeArguments);
- } else if (type is FunctionTypeImpl) {
- FunctionTypeImpl functionType = type as FunctionTypeImpl;
- type = functionType.substitute3(typeArguments);
- } else {
- // TODO(brianwilkerson) Report this internal error.
- }
+ type = _instantiateType(type, typeArguments);
} else {
//
// Check for the case where there are no type arguments given for a
// parameterized type.
//
- List<DartType> parameters = _getTypeArguments(type);
+ List<DartType> parameters = _getTypeParameters(type);
int parameterCount = parameters.length;
if (parameterCount > 0) {
DynamicTypeImpl dynamicType = DynamicTypeImpl.instance;
@@ -14480,7 +14990,7 @@
for (int i = 0; i < parameterCount; i++) {
arguments[i] = dynamicType;
}
- type = type.substitute2(arguments, parameters);
+ type = _instantiateType(type, arguments);
}
}
typeName.staticType = type;
@@ -14665,11 +15175,11 @@
* @param type the type whole type arguments are to be returned
* @return the type arguments associated with the given type
*/
- List<DartType> _getTypeArguments(DartType type) {
+ List<DartType> _getTypeParameters(DartType type) {
if (type is InterfaceType) {
return type.typeArguments;
} else if (type is FunctionType) {
- return type.typeArguments;
+ return TypeParameterTypeImpl.getTypes(type.boundTypeParameters);
}
return DartType.EMPTY_LIST;
}
@@ -14708,6 +15218,17 @@
return type;
}
+ DartType _instantiateType(DartType type, List<DartType> typeArguments) {
+ if (type is InterfaceTypeImpl) {
+ return type.substitute4(typeArguments);
+ } else if (type is FunctionTypeImpl) {
+ return type.instantiate(typeArguments);
+ } else {
+ // TODO(brianwilkerson) Report this internal error.
+ return type;
+ }
+ }
+
/**
* Checks if the given type name is used as the type in an as expression.
*
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 24fec62..79cd48f 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -208,17 +208,6 @@
}
}
-// /**
-// * Return the offset of the first character on the line with the given
-// * [lineNumber].
-// */
-// int getLineOffset(int lineNumber) {
-// if (lineNumber < 0 || lineNumber >= _lineStarts.length) {
-// throw new ArgumentError('Invalid line number: $lineNumber');
-// }
-// return _lineStarts[lineNumber];
-// }
-
/**
* Return the location information for the character at the given offset.
*
@@ -258,6 +247,17 @@
return new LineInfo_Location(min + 1, offset - _lineStarts[min] + 1);
}
+
+ /**
+ * Return the offset of the first character on the line with the given
+ * [lineNumber].
+ */
+ int getOffsetOfLine(int lineNumber) {
+ if (lineNumber < 0 || lineNumber >= _lineStarts.length) {
+ throw new ArgumentError('Invalid line number: $lineNumber');
+ }
+ return _lineStarts[lineNumber];
+ }
}
/**
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 4343549..a746a1e 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -13,6 +13,7 @@
import 'java_engine.dart';
import 'resolver.dart';
import 'scanner.dart' as sc;
+import 'utilities_dart.dart';
/**
* Instances of the class `StaticTypeAnalyzer` perform two type-related tasks. First, they
@@ -93,6 +94,83 @@
}
/**
+ * Given a constructor name [node] and a type [type], record an inferred type
+ * for the constructor if in strong mode. This is used to fill in any
+ * inferred type parameters found by the resolver.
+ */
+ void inferConstructorName(ConstructorName node, InterfaceType type) {
+ if (_strongMode) {
+ node.type.type = type;
+ _resolver.inferenceContext.recordInference(node.parent, type);
+ }
+ return;
+ }
+
+ /**
+ * Given a formal parameter list and a function type use the function type
+ * to infer types for any of the parameters which have implicit (missing)
+ * types. Only infers types in strong mode. Returns true if inference
+ * has occurred.
+ */
+ bool inferFormalParameterList(
+ FormalParameterList node, DartType functionType) {
+ bool inferred = false;
+ if (_strongMode && node != null && functionType is FunctionType) {
+ void inferType(ParameterElementImpl p, DartType inferredType) {
+ // Check that there is no declared type, and that we have not already
+ // inferred a type in some fashion.
+ if (p.hasImplicitType &&
+ (p.type == null || p.type.isDynamic) &&
+ !inferredType.isDynamic) {
+ p.type = inferredType;
+ inferred = true;
+ }
+ }
+
+ List<ParameterElement> parameters = node.parameterElements;
+
+ {
+ List<DartType> normalParameterTypes = functionType.normalParameterTypes;
+ int normalCount = normalParameterTypes.length;
+ Iterable<ParameterElement> required = parameters
+ .where((p) => p.parameterKind == ParameterKind.REQUIRED)
+ .take(normalCount);
+ int index = 0;
+ for (ParameterElementImpl p in required) {
+ inferType(p, normalParameterTypes[index++]);
+ }
+ }
+
+ {
+ List<DartType> optionalParameterTypes =
+ functionType.optionalParameterTypes;
+ int optionalCount = optionalParameterTypes.length;
+ Iterable<ParameterElement> optional = parameters
+ .where((p) => p.parameterKind == ParameterKind.POSITIONAL)
+ .take(optionalCount);
+ int index = 0;
+ for (ParameterElementImpl p in optional) {
+ inferType(p, optionalParameterTypes[index++]);
+ }
+ }
+
+ {
+ Map<String, DartType> namedParameterTypes =
+ functionType.namedParameterTypes;
+ Iterable<ParameterElement> named =
+ parameters.where((p) => p.parameterKind == ParameterKind.NAMED);
+ for (ParameterElementImpl p in named) {
+ if (!namedParameterTypes.containsKey(p.name)) {
+ continue;
+ }
+ inferType(p, namedParameterTypes[p.name]);
+ }
+ }
+ }
+ return inferred;
+ }
+
+ /**
* The Dart Language Specification, 12.5: <blockquote>The static type of a string literal is
* `String`.</blockquote>
*/
@@ -381,8 +459,19 @@
}
ExecutableElementImpl functionElement =
node.element as ExecutableElementImpl;
- functionElement.returnType =
- _computeStaticReturnTypeOfFunctionExpression(node);
+ DartType computedType = _computeStaticReturnTypeOfFunctionExpression(node);
+ if (_strongMode) {
+ DartType functionType = InferenceContext.getType(node);
+ if (functionType is FunctionType) {
+ DartType returnType = functionType.returnType;
+ if ((computedType.isDynamic || computedType.isBottom) &&
+ !(returnType.isDynamic || returnType.isBottom)) {
+ computedType = returnType;
+ _resolver.inferenceContext.recordInference(node, functionType);
+ }
+ }
+ }
+ functionElement.returnType = computedType;
_recordPropagatedTypeOfFunction(functionElement, node.body);
_recordStaticType(node, node.element.type);
return null;
@@ -522,6 +611,15 @@
staticType = argumentType;
}
}
+ } else {
+ DartType contextType = InferenceContext.getType(node);
+ if (_strongMode &&
+ contextType is InterfaceType &&
+ contextType.typeArguments.length == 1 &&
+ contextType.element == _typeProvider.listType.element) {
+ staticType = contextType.typeArguments[0];
+ _resolver.inferenceContext.recordInference(node, contextType);
+ }
}
_recordStaticType(
node, _typeProvider.listType.substitute4(<DartType>[staticType]));
@@ -559,6 +657,16 @@
staticValueType = entryValueType;
}
}
+ } else {
+ DartType contextType = InferenceContext.getType(node);
+ if (_strongMode &&
+ contextType is InterfaceType &&
+ contextType.typeArguments.length == 2 &&
+ contextType.element == _typeProvider.mapType.element) {
+ staticKeyType = contextType.typeArguments[0] ?? staticKeyType;
+ staticValueType = contextType.typeArguments[1] ?? staticValueType;
+ _resolver.inferenceContext.recordInference(node, contextType);
+ }
}
_recordStaticType(
node,
@@ -1679,6 +1787,25 @@
}
/**
+ * Given a local variable declaration and its initializer, attempt to infer
+ * a type for the local variable declaration based on the initializer.
+ * Inference is only done if an explicit type is not present, and if
+ * inferring a type improves the type.
+ */
+ void _inferLocalVariableType(
+ VariableDeclaration node, Expression initializer) {
+ if (initializer != null &&
+ (node.parent as VariableDeclarationList).type == null &&
+ (node.element is LocalVariableElementImpl) &&
+ (initializer.staticType != null) &&
+ (!initializer.staticType.isBottom)) {
+ LocalVariableElementImpl element = node.element;
+ element.type = initializer.staticType;
+ node.name.staticType = initializer.staticType;
+ }
+ }
+
+ /**
* Given a method invocation [node], attempt to infer a better
* type for the result.
*/
@@ -1689,17 +1816,44 @@
}
/**
- * Given a method invocation [node], attempt to infer a better
- * type for the result using an ad-hoc list of psuedo-generic methods.
+ * Given a generic method invocation [node], attempt to infer the method's
+ * type variables, using the actual types of the arguments.
*/
bool _inferMethodInvocationGeneric(MethodInvocation node) {
- DartType inferredType = _matchGeneric(node);
- // TODO(vsm): If the inferred type is not a subtype,
- // should we use a GLB instead?
- if (inferredType != null &&
- _typeSystem.isSubtypeOf(inferredType, node.staticType)) {
- _recordStaticType(node, inferredType);
- return true;
+ Element element = node.methodName.staticElement;
+ DartType fnType = node.methodName.staticType;
+ TypeSystem ts = _typeSystem;
+ // TODO(jmesserly): once we allow explicitly passed typeArguments, we need
+ // to only do this if node.typeArguments == null.
+ if (element is ExecutableElement &&
+ fnType is FunctionTypeImpl &&
+ ts is StrongTypeSystemImpl) {
+ // 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();
+
+ FunctionType inferred = ts.inferCallFromArguments(
+ _typeProvider, fnType, paramTypes, argTypes);
+ if (inferred != fnType) {
+ // TODO(jmesserly): inference should be happening earlier, which would
+ // allow these parameters to be correct from the get-go.
+
+ List<ParameterElement> inferredParameters = inferred.parameters;
+ List<ParameterElement> correspondingParams =
+ new List<ParameterElement>();
+ for (Expression arg in arguments) {
+ int i = element.parameters.indexOf(arg.staticParameterElement);
+ correspondingParams.add(inferredParameters[i]);
+ }
+ node.argumentList.correspondingStaticParameters = correspondingParams;
+ _recordStaticType(node.methodName, inferred);
+ _recordStaticType(node, inferred.returnType);
+ return true;
+ }
}
return false;
}
@@ -1766,25 +1920,6 @@
}
/**
- * Given a local variable declaration and its initializer, attempt to infer
- * a type for the local variable declaration based on the initializer.
- * Inference is only done if an explicit type is not present, and if
- * inferring a type improves the type.
- */
- void _inferLocalVariableType(
- VariableDeclaration node, Expression initializer) {
- if (initializer != null &&
- (node.parent as VariableDeclarationList).type == null &&
- (node.element is LocalVariableElementImpl) &&
- (initializer.staticType != null) &&
- (!initializer.staticType.isBottom)) {
- LocalVariableElementImpl element = node.element;
- element.type = initializer.staticType;
- node.name.staticType = initializer.staticType;
- }
- }
-
- /**
* Given a property access [node] with static type [nodeType],
* and [id] is the property name being accessed, infer a type for the
* access itself and its constituent components if the access is to one of the
@@ -1862,91 +1997,6 @@
}
/**
- * Return a more specialized type for a method invocation based on
- * an ad-hoc list of pseudo-generic methods.
- */
- DartType _matchGeneric(MethodInvocation node) {
- Element e = node.methodName.staticElement;
-
- if (e == null || e.name == null) {
- return null;
- }
-
- List<DartType> arguments =
- node.argumentList.arguments.map((arg) => arg.staticType).toList();
-
- bool matchInvocation(DartType t, int c) {
- return (node.realTarget != null) &&
- node.realTarget.staticType.isSubtypeOf(t) &&
- arguments.length == c;
- }
-
- switch (e.name) {
- case 'max':
- case 'min':
- if (e.library.source.uri.toString() == 'dart:math' &&
- arguments.length == 2) {
- DartType tx = arguments[0];
- DartType ty = arguments[1];
- if (tx == ty &&
- (tx == _typeProvider.intType || tx == _typeProvider.doubleType)) {
- return tx;
- }
- }
- return null;
- case 'wait':
- if (matchInvocation(_typeProvider.futureType, 1)) {
- DartType tx = arguments[0];
- // Iterable<Future<T>> -> Future<List<T>>
- DartType futureType =
- _findIteratedType(tx, _typeProvider.iterableType);
- if (futureType.element != _typeProvider.futureType.element) {
- return null;
- }
- List<DartType> typeArguments =
- (futureType as InterfaceType).typeArguments;
- if (typeArguments.length != 1) {
- return null;
- }
- DartType baseType = typeArguments[0];
- if (baseType.isDynamic) {
- return null;
- }
- return _typeProvider.futureType.substitute4([
- _typeProvider.listType.substitute4([baseType])
- ]);
- }
- return null;
- case 'map':
- if (matchInvocation(_typeProvider.iterableDynamicType, 1)) {
- DartType tx = arguments[0];
- return (tx is FunctionType)
- ? _typeProvider.iterableType.substitute4([tx.returnType])
- : null;
- }
- return null;
- case 'fold':
- if (matchInvocation(_typeProvider.iterableDynamicType, 2)) {
- DartType tx = arguments[0];
- DartType ty = arguments[1];
- // TODO(vsm): LUB?
- return (ty is FunctionType && tx == ty.returnType) ? tx : null;
- }
- return null;
- case 'then':
- if (matchInvocation(_typeProvider.futureDynamicType, 1)) {
- DartType tx = arguments[0];
- return (tx is FunctionType)
- ? _typeProvider.futureType.substitute4([tx.returnType])
- : null;
- }
- return null;
- default:
- return null;
- }
- }
-
- /**
* Record that the propagated type of the given node is the given type.
*
* @param expression the node whose type is to be recorded
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index dff33e9..4414103 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -49,19 +49,10 @@
if (parameterNames != null) {
int count = parameterNames.length;
if (count > 0) {
- List<TypeParameterElementImpl> typeParameters =
- new List<TypeParameterElementImpl>(count);
- List<TypeParameterTypeImpl> typeParameterTypes =
- new List<TypeParameterTypeImpl>(count);
- for (int i = 0; i < count; i++) {
- TypeParameterElementImpl typeParameter =
- typeParameterElement(parameterNames[i]);
- typeParameters[i] = typeParameter;
- typeParameterTypes[i] = new TypeParameterTypeImpl(typeParameter);
- typeParameter.type = typeParameterTypes[i];
- }
- element.typeParameters = typeParameters;
- type.typeArguments = typeParameterTypes;
+ element.typeParameters = typeParameters(parameterNames);
+ type.typeArguments = new List<DartType>.from(
+ element.typeParameters.map((p) => p.type),
+ growable: false);
}
}
return element;
@@ -243,12 +234,12 @@
functionElement4(functionName, null, null, null, null);
static FunctionElementImpl functionElement2(
- String functionName, ClassElement returnElement) =>
+ String functionName, TypeDefiningElement returnElement) =>
functionElement3(functionName, returnElement, null, null);
static FunctionElementImpl functionElement3(
String functionName,
- ClassElement returnElement,
+ TypeDefiningElement returnElement,
List<TypeDefiningElement> normalParameters,
List<TypeDefiningElement> optionalParameters) {
// We don't create parameter elements because we don't have parameter names
@@ -611,4 +602,25 @@
element.type = new TypeParameterTypeImpl(element);
return element;
}
+
+ static List<TypeParameterElement> typeParameters(List<String> names) {
+ int count = names.length;
+ if (count == 0) {
+ return TypeParameterElement.EMPTY_LIST;
+ }
+ List<TypeParameterElementImpl> typeParameters =
+ new List<TypeParameterElementImpl>(count);
+ for (int i = 0; i < count; i++) {
+ typeParameters[i] = typeParameterWithType(names[i]);
+ }
+ return typeParameters;
+ }
+
+ static TypeParameterElementImpl typeParameterWithType(String name,
+ [DartType bound]) {
+ TypeParameterElementImpl typeParameter = typeParameterElement(name);
+ typeParameter.type = new TypeParameterTypeImpl(typeParameter);
+ typeParameter.bound = bound;
+ return typeParameter;
+ }
}
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index ef6bbfb..f731360 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -11,10 +11,8 @@
import 'resolver.dart' show TypeProvider;
typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
-
typedef bool _SubtypeChecker<T>(T t1, T t2);
-
/**
* Implementation of [TypeSystem] using the strong mode rules.
* https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
@@ -31,6 +29,105 @@
return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
}
+ /// Given a function type with generic type parameters, infer the type
+ /// parameters from the actual argument types, and return it. If we can't.
+ /// returns the original function type.
+ ///
+ /// Concretely, given a function type with parameter types P0, P1, ... Pn,
+ /// result type R, and generic type parameters T0, T1, ... Tm, use the
+ /// argument types A0, A1, ... An to solve for the type parameters.
+ ///
+ /// For each parameter Pi, we want to ensure that Ai <: Pi. We can do this by
+ /// running the subtype algorithm, and when we reach a type parameter Pj,
+ /// recording the lower or upper bound it must satisfy. At the end, all
+ /// constraints can be combined to determine the type.
+ ///
+ /// As a simplification, we do not actually store all constraints on each type
+ /// parameter Pj. Instead we track Uj and Lj where U is the upper bound and
+ /// L is the lower bound of that type parameter.
+ FunctionType inferCallFromArguments(
+ TypeProvider typeProvider,
+ FunctionTypeImpl fnType,
+ List<DartType> correspondingParameterTypes,
+ List<DartType> argumentTypes) {
+ if (fnType.boundTypeParameters.isEmpty) {
+ return fnType;
+ }
+
+ List<TypeParameterType> fnTypeParams =
+ TypeParameterTypeImpl.getTypes(fnType.boundTypeParameters);
+
+ // Create a TypeSystem that will allow certain type parameters to be
+ // inferred. It will optimistically assume these type parameters can be
+ // subtypes (or supertypes) as necessary, and track the constraints that
+ // are implied by this.
+ var inferringTypeSystem =
+ new _StrongInferenceTypeSystem(typeProvider, fnTypeParams);
+
+ for (int i = 0; i < argumentTypes.length; i++) {
+ // Try to pass each argument to each parameter, recording any type
+ // parameter bounds that were implied by this assignment.
+ inferringTypeSystem.isSubtypeOf(
+ argumentTypes[i], correspondingParameterTypes[i]);
+ }
+
+ var inferredTypes = new List<DartType>.from(fnTypeParams, growable: false);
+ for (int i = 0; i < fnTypeParams.length; i++) {
+ TypeParameterType typeParam = fnTypeParams[i];
+ _TypeParameterBound bound = inferringTypeSystem._bounds[typeParam];
+
+ // Now we've computed lower and upper bounds for each type parameter.
+ //
+ // To decide on which type to assign, we look at the return type and see
+ // if the type parameter occurs in covariant or contravariant positions.
+ //
+ // If the type is "passed in" at all, or if our lower bound was bottom,
+ // we choose the upper bound as being the most useful.
+ //
+ // Otherwise we choose the more precise lower bound.
+ _TypeParameterVariance variance =
+ new _TypeParameterVariance.from(typeParam, fnType.returnType);
+
+ inferredTypes[i] =
+ variance.passedIn || bound.lower.isBottom ? bound.upper : bound.lower;
+
+ // Assumption: if the current type parameter has an "extends" clause
+ // that refers to another type variable we are inferring, it will appear
+ // before us or in this list position. For example:
+ //
+ // <TFrom, TTo extends TFrom>
+ //
+ // We may infer TTo is TFrom. In that case, we already know what TFrom
+ // is inferred as, so we can substitute it now. This also handles more
+ // complex cases such as:
+ //
+ // <TFrom, TTo extends Iterable<TFrom>>
+ //
+ // Or if the type parameter's bound depends on itself such as:
+ //
+ // <T extends Clonable<T>>
+ inferredTypes[i] =
+ inferredTypes[i].substitute2(inferredTypes, fnTypeParams);
+
+ // See if this actually worked.
+ // If not, fall back to the known upper bound (if any) or `dynamic`.
+ if (inferredTypes[i].isBottom ||
+ !isSubtypeOf(inferredTypes[i],
+ bound.upper.substitute2(inferredTypes, fnTypeParams)) ||
+ !isSubtypeOf(bound.lower.substitute2(inferredTypes, fnTypeParams),
+ inferredTypes[i])) {
+ inferredTypes[i] = DynamicTypeImpl.instance;
+ if (typeParam.element.bound != null) {
+ inferredTypes[i] =
+ typeParam.element.bound.substitute2(inferredTypes, fnTypeParams);
+ }
+ }
+ }
+
+ // Return the instantiated type.
+ return fnType.instantiate(inferredTypes);
+ }
+
// TODO(leafp): Document the rules in play here
@override
bool isAssignableTo(DartType fromType, DartType toType) {
@@ -68,6 +165,9 @@
return _isSubtypeOf(leftType, rightType, null);
}
+ // Given a type t, if t is an interface type with a call method
+ // defined, return the function type for the call method, otherwise
+ // return null.
FunctionType _getCallMethodType(DartType t) {
if (t is InterfaceType) {
return t.lookUpInheritedMethod("call")?.type;
@@ -75,9 +175,6 @@
return null;
}
- // Given a type t, if t is an interface type with a call method
- // defined, return the function type for the call method, otherwise
- // return null.
_GuardedSubtypeChecker<DartType> _guard(
_GuardedSubtypeChecker<DartType> check) {
return (DartType t1, DartType t2, Set<Element> visited) {
@@ -96,6 +193,14 @@
};
}
+ /// If [t1] or [t2] is a type parameter we are inferring, update its bound.
+ /// Returns `true` if we could possibly find a compatible type,
+ /// otherwise `false`.
+ bool _inferTypeParameterSubtypeOf(
+ DartType t1, DartType t2, Set<Element> visited) {
+ return false;
+ }
+
bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
return (t.isDynamic && dynamicIsBottom) || t.isBottom;
}
@@ -245,6 +350,8 @@
{bool dynamicIsBottom: false}) {
// Guard recursive calls
_GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+ _GuardedSubtypeChecker<DartType> guardedInferTypeParameter =
+ _guard(_inferTypeParameterSubtypeOf);
if (t1 == t2) {
return true;
@@ -263,7 +370,7 @@
// Trivially false.
if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
_isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
- return false;
+ return guardedInferTypeParameter(t1, t2, visited);
}
// S <: T where S is a type variable
@@ -272,13 +379,15 @@
// So only true if bound of S is S' and
// S' <: T
if (t1 is TypeParameterType) {
+ if (guardedInferTypeParameter(t1, t2, visited)) {
+ return true;
+ }
DartType bound = t1.element.bound;
- if (bound == null) return false;
- return guardedSubtype(bound, t2, visited);
+ return bound == null ? false : guardedSubtype(bound, t2, visited);
}
if (t2 is TypeParameterType) {
- return false;
+ return guardedInferTypeParameter(t1, t2, visited);
}
if (t1.isVoid || t2.isVoid) {
@@ -316,7 +425,6 @@
}
}
-
/**
* The interface `TypeSystem` defines the behavior of an object representing
* the type system. This provides a common location to put methods that act on
@@ -449,3 +557,161 @@
return leftType.isSubtypeOf(rightType);
}
}
+
+/// Tracks upper and lower type bounds for a set of type parameters.
+class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
+ final TypeProvider _typeProvider;
+ final Map<TypeParameterType, _TypeParameterBound> _bounds;
+
+ _StrongInferenceTypeSystem(
+ this._typeProvider, Iterable<TypeParameterType> typeParams)
+ : _bounds = new Map.fromIterable(typeParams, value: (t) {
+ _TypeParameterBound bound = new _TypeParameterBound();
+ if (t.element.bound != null) bound.upper = t.element.bound;
+ return bound;
+ });
+
+ @override
+ bool _inferTypeParameterSubtypeOf(
+ DartType t1, DartType t2, Set<Element> visited) {
+ if (t1 is TypeParameterType) {
+ _TypeParameterBound bound = _bounds[t1];
+ if (bound != null) {
+ _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+
+ DartType newUpper = t2;
+ if (guardedSubtype(bound.upper, newUpper, visited)) {
+ // upper bound already covers this. Nothing to do.
+ } else if (guardedSubtype(newUpper, bound.upper, visited)) {
+ // update to the new, more precise upper bound.
+ bound.upper = newUpper;
+ } else {
+ // Failed to find an upper bound. Use bottom to signal no solution.
+ bound.upper = BottomTypeImpl.instance;
+ }
+ // Optimistically assume we will be able to satisfy the constraint.
+ return true;
+ }
+ }
+ if (t2 is TypeParameterType) {
+ _TypeParameterBound bound = _bounds[t2];
+ if (bound != null) {
+ bound.lower = getLeastUpperBound(_typeProvider, bound.lower, t1);
+ // Optimistically assume we will be able to satisfy the constraint.
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+/// An [upper] and [lower] bound for a type variable.
+class _TypeParameterBound {
+ /// The upper bound of the type parameter. In other words, T <: upperBound.
+ ///
+ /// In Dart this can be written as `<T extends UpperBoundType>`.
+ ///
+ /// In inference, this can happen as a result of parameters of function type.
+ /// For example, consider a signature like:
+ ///
+ /// T reduce<T>(List<T> values, T f(T x, T y));
+ ///
+ /// and a call to it like:
+ ///
+ /// reduce(values, (num x, num y) => ...);
+ ///
+ /// From the function expression's parameters, we conclude `T <: num`. We may
+ /// still be able to conclude a different [lower] based on `values` or
+ /// the type of the elided `=> ...` body. For example:
+ ///
+ /// reduce(['x'], (num x, num y) => 'hi');
+ ///
+ /// Here the [lower] will be `String` and the upper bound will be `num`,
+ /// which cannot be satisfied, so this is ill typed.
+ DartType upper = DynamicTypeImpl.instance;
+
+ /// The lower bound of the type parameter. In other words, lowerBound <: T.
+ ///
+ /// This kind of constraint cannot be expressed in Dart, but it applies when
+ /// we're doing inference. For example, consider a signature like:
+ ///
+ /// T pickAtRandom<T>(T x, T y);
+ ///
+ /// and a call to it like:
+ ///
+ /// pickAtRandom(1, 2.0)
+ ///
+ /// when we see the first parameter is an `int`, we know that `int <: T`.
+ /// When we see `double` this implies `double <: T`.
+ /// Combining these constraints results in a lower bound of `num`.
+ ///
+ /// In general, we choose the lower bound as our inferred type, so we can
+ /// offer the most constrained (strongest) result type.
+ DartType lower = BottomTypeImpl.instance;
+}
+
+/// Records what positions a type parameter is used in.
+class _TypeParameterVariance {
+ /// The type parameter is a value passed out. It must satisfy T <: S,
+ /// where T is the type parameter and S is what it's assigned to.
+ ///
+ /// For example, this could be the return type, or a parameter to a parameter:
+ ///
+ /// TOut method<TOut>(void f(TOut t));
+ bool passedOut = false;
+
+ /// The type parameter is a value passed in. It must satisfy S <: T,
+ /// where T is the type parameter and S is what's being assigned to it.
+ ///
+ /// For example, this could be a parameter type, or the parameter of the
+ /// return value:
+ ///
+ /// typedef void Func<T>(T t);
+ /// Func<TIn> method<TIn>(TIn t);
+ bool passedIn = false;
+
+ _TypeParameterVariance.from(TypeParameterType typeParam, DartType type) {
+ _visitType(typeParam, type, false);
+ }
+
+ void _visitFunctionType(
+ TypeParameterType typeParam, FunctionType type, bool paramIn) {
+ for (ParameterElement p in type.parameters) {
+ // If a lambda L is passed in to a function F, the the parameters are
+ // "passed out" of F into L. Thus we invert the "passedIn" state.
+ _visitType(typeParam, p.type, !paramIn);
+ }
+ // If a lambda L is passed in to a function F, and we call L, the result of
+ // L is then "passed in" to F. So we keep the "passedIn" state.
+ _visitType(typeParam, type.returnType, paramIn);
+ }
+
+ void _visitInterfaceType(
+ TypeParameterType typeParam, InterfaceType type, bool paramIn) {
+ // Currently in "strong mode" generic type parameters are covariant.
+ //
+ // This means we treat them as "out" type parameters similar to the result
+ // of a function, and thus they follow the same rules.
+ //
+ // For example, we pass in Iterable<T> as a parameter. Then we iterate over
+ // it. The "T" is essentially an input. So it keeps the same state.
+ // Similarly, if we return an Iterable<T> it's equivalent to returning a T.
+ for (DartType typeArg in type.typeArguments) {
+ _visitType(typeParam, typeArg, paramIn);
+ }
+ }
+
+ void _visitType(TypeParameterType typeParam, DartType type, bool paramIn) {
+ if (type == typeParam) {
+ if (paramIn) {
+ passedIn = true;
+ } else {
+ passedOut = true;
+ }
+ } else if (type is FunctionType) {
+ _visitFunctionType(typeParam, type, paramIn);
+ } else if (type is InterfaceType) {
+ _visitInterfaceType(typeParam, type, paramIn);
+ }
+ }
+}
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index a067dcc..dbd8963 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -197,6 +197,8 @@
registerExtension(
taskId, ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR);
registerExtension(taskId, ComputeLibraryCycleTask.DESCRIPTOR);
+ registerExtension(
+ taskId, ComputePropagableVariableDependenciesTask.DESCRIPTOR);
registerExtension(taskId, ContainingLibrariesTask.DESCRIPTOR);
registerExtension(taskId, DartErrorsTask.DESCRIPTOR);
registerExtension(taskId, EvaluateUnitConstantsTask.DESCRIPTOR);
@@ -211,11 +213,17 @@
registerExtension(taskId, LibraryUnitErrorsTask.DESCRIPTOR);
registerExtension(taskId, ParseDartTask.DESCRIPTOR);
registerExtension(taskId, PartiallyResolveUnitReferencesTask.DESCRIPTOR);
+ registerExtension(
+ taskId, PropagateVariableTypesInLibraryClosureTask.DESCRIPTOR);
+ registerExtension(taskId, PropagateVariableTypesInLibraryTask.DESCRIPTOR);
+ registerExtension(taskId, PropagateVariableTypesInUnitTask.DESCRIPTOR);
+ registerExtension(taskId, PropagateVariableTypeTask.DESCRIPTOR);
registerExtension(taskId, ReadyLibraryElement2Task.DESCRIPTOR);
registerExtension(taskId, ReadyLibraryElement5Task.DESCRIPTOR);
+ registerExtension(taskId, ReadyLibraryElement6Task.DESCRIPTOR);
registerExtension(taskId, ReadyResolvedUnitTask.DESCRIPTOR);
- registerExtension(taskId, ReadyResolvedUnit9Task.DESCRIPTOR);
registerExtension(taskId, ReadyResolvedUnit10Task.DESCRIPTOR);
+ registerExtension(taskId, ReadyResolvedUnit11Task.DESCRIPTOR);
registerExtension(taskId, ResolveInstanceFieldsInUnitTask.DESCRIPTOR);
registerExtension(taskId, ResolveLibraryReferencesTask.DESCRIPTOR);
registerExtension(taskId, ResolveLibraryTypeNamesTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/summary/format.dart b/pkg/analyzer/lib/src/summary/format.dart
index 61a4978..4974b99 100644
--- a/pkg/analyzer/lib/src/summary/format.dart
+++ b/pkg/analyzer/lib/src/summary/format.dart
@@ -130,13 +130,16 @@
class PrelinkedReference {
int _dependency;
PrelinkedReferenceKind _kind;
+ int _unit;
PrelinkedReference.fromJson(Map json)
: _dependency = json["dependency"],
- _kind = json["kind"] == null ? null : PrelinkedReferenceKind.values[json["kind"]];
+ _kind = json["kind"] == null ? null : PrelinkedReferenceKind.values[json["kind"]],
+ _unit = json["unit"];
int get dependency => _dependency ?? 0;
PrelinkedReferenceKind get kind => _kind ?? PrelinkedReferenceKind.classOrEnum;
+ int get unit => _unit ?? 0;
}
class PrelinkedReferenceBuilder {
@@ -158,13 +161,21 @@
}
}
+ void set unit(int _value) {
+ assert(!_json.containsKey("unit"));
+ if (_value != null) {
+ _json["unit"] = _value;
+ }
+ }
+
Map finish() => _json;
}
-PrelinkedReferenceBuilder encodePrelinkedReference(builder.BuilderContext builderContext, {int dependency, PrelinkedReferenceKind kind}) {
+PrelinkedReferenceBuilder encodePrelinkedReference(builder.BuilderContext builderContext, {int dependency, PrelinkedReferenceKind kind, int unit}) {
PrelinkedReferenceBuilder builder = new PrelinkedReferenceBuilder(builderContext);
builder.dependency = dependency;
builder.kind = kind;
+ builder.unit = unit;
return builder;
}
diff --git a/pkg/analyzer/lib/src/summary/summarize_elements.dart b/pkg/analyzer/lib/src/summary/summarize_elements.dart
index 79a73a3..1ad8dd7 100644
--- a/pkg/analyzer/lib/src/summary/summarize_elements.dart
+++ b/pkg/analyzer/lib/src/summary/summarize_elements.dart
@@ -555,6 +555,10 @@
} else {
b.reference = referenceMap.putIfAbsent(element, () {
assert(unlinkedReferences.length == prelinkedReferences.length);
+ CompilationUnitElement unitElement =
+ element.getAncestor((Element e) => e is CompilationUnitElement);
+ int unit = dependentLibrary.units.indexOf(unitElement);
+ assert(unit != -1);
int index = unlinkedReferences.length;
// TODO(paulberry): set UnlinkedReference.prefix.
unlinkedReferences
@@ -563,7 +567,8 @@
dependency: serializeDependency(dependentLibrary),
kind: element is FunctionTypeAliasElement
? PrelinkedReferenceKind.typedef
- : PrelinkedReferenceKind.classOrEnum));
+ : PrelinkedReferenceKind.classOrEnum,
+ unit: unit));
return index;
});
}
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 2aae1a1..1a5046d 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -286,6 +286,28 @@
cachingPolicy: ELEMENT_CACHING_POLICY);
/**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * [LIBRARY_ELEMENT5] plus propagated types for propagable variables.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT6 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT6', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
+ * The partial [LibraryElement] associated with a library.
+ *
+ * [LIBRARY_ELEMENT6] for the library and its import/export closure.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<LibraryElement> LIBRARY_ELEMENT7 =
+ new ResultDescriptor<LibraryElement>('LIBRARY_ELEMENT7', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
* The flag specifying whether all analysis errors are computed in a specific
* library.
*
@@ -338,6 +360,36 @@
'PARSE_ERRORS', AnalysisError.NO_ERRORS);
/**
+ * A list of the [VariableElement]s whose type should be known to propagate
+ * the type of another variable (the target).
+ *
+ * The result is only available for [VariableElement]s.
+ */
+final ListResultDescriptor<VariableElement> PROPAGABLE_VARIABLE_DEPENDENCIES =
+ new ListResultDescriptor<VariableElement>(
+ 'PROPAGABLE_VARIABLE_DEPENDENCIES', null);
+
+/**
+ * A list of the [VariableElement]s defined in a unit whose type might be
+ * propagated. This includes variables defined at the library level as well as
+ * static and instance members inside classes.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<VariableElement> PROPAGABLE_VARIABLES_IN_UNIT =
+ new ListResultDescriptor<VariableElement>(
+ 'PROPAGABLE_VARIABLES_IN_UNIT', null);
+
+/**
+ * An propagable variable ([VariableElement]) whose type has been propagated.
+ *
+ * The result is only available for [VariableElement]s.
+ */
+final ResultDescriptor<VariableElement> PROPAGATED_VARIABLE =
+ new ResultDescriptor<VariableElement>('PROPAGATED_VARIABLE', null,
+ cachingPolicy: ELEMENT_CACHING_POLICY);
+
+/**
* The flag specifying that [LIBRARY_ELEMENT2] is ready for a library and its
* import/export closure.
*
@@ -356,6 +408,15 @@
new ResultDescriptor<bool>('READY_LIBRARY_ELEMENT5', false);
/**
+ * The flag specifying that [LIBRARY_ELEMENT6] is ready for a library and its
+ * import/export closure.
+ *
+ * The result is only available for [Source]s representing a library.
+ */
+final ResultDescriptor<bool> READY_LIBRARY_ELEMENT6 =
+ new ResultDescriptor<bool>('READY_LIBRARY_ELEMENT6', false);
+
+/**
* The flag specifying that [RESOLVED_UNIT] is ready for all of the units of a
* library and its import/export closure.
*
@@ -374,13 +435,13 @@
new ResultDescriptor<bool>('READY_RESOLVED_UNIT10', false);
/**
- * The flag specifying that [RESOLVED_UNIT9] is ready for all of the units of a
+ * The flag specifying that [RESOLVED_UNIT11] is ready for all of the units of a
* library and its import/export closure.
*
* The result is only available for [Source]s representing a library.
*/
-final ResultDescriptor<bool> READY_RESOLVED_UNIT9 =
- new ResultDescriptor<bool>('READY_RESOLVED_UNIT9', false);
+final ResultDescriptor<bool> READY_RESOLVED_UNIT11 =
+ new ResultDescriptor<bool>('READY_RESOLVED_UNIT11', false);
/**
* The names (resolved and not) referenced by a unit.
@@ -427,7 +488,7 @@
/**
* The resolved [CompilationUnit] associated with a compilation unit, with
- * constants resolved.
+ * constants not yet resolved.
*
* The result is only available for [LibrarySpecificUnit]s.
*/
@@ -436,6 +497,16 @@
cachingPolicy: AST_CACHING_POLICY);
/**
+ * The resolved [CompilationUnit] associated with a compilation unit, with
+ * constants resolved.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ResultDescriptor<CompilationUnit> RESOLVED_UNIT11 =
+ new ResultDescriptor<CompilationUnit>('RESOLVED_UNIT11', null,
+ cachingPolicy: AST_CACHING_POLICY);
+
+/**
* The partially resolved [CompilationUnit] associated with a compilation unit.
*
* Tasks that use this value as an input can assume that the [SimpleIdentifier]s
@@ -493,7 +564,8 @@
* The partially resolved [CompilationUnit] associated with a compilation unit.
*
* In addition to what is true of a [RESOLVED_UNIT5], tasks that use this value
- * as an input can assume that the types of static variables have been inferred.
+ * as an input can assume that the types of final variables have been
+ * propagated.
*
* The result is only available for [LibrarySpecificUnit]s.
*/
@@ -505,8 +577,7 @@
* The partially resolved [CompilationUnit] associated with a compilation unit.
*
* In addition to what is true of a [RESOLVED_UNIT6], tasks that use this value
- * as an input can assume that the initializers of instance variables have been
- * re-resolved.
+ * as an input can assume that the types of static variables have been inferred.
*
* The result is only available for [LibrarySpecificUnit]s.
*/
@@ -515,9 +586,11 @@
cachingPolicy: AST_CACHING_POLICY);
/**
- * The resolved [CompilationUnit] associated with a compilation unit in which
- * the types of class members have been inferred in addition to everything that
- * is true of a [RESOLVED_UNIT7].
+ * The partially resolved [CompilationUnit] associated with a compilation unit.
+ *
+ * In addition to what is true of a [RESOLVED_UNIT7], tasks that use this value
+ * as an input can assume that the initializers of instance variables have been
+ * re-resolved.
*
* The result is only available for [LibrarySpecificUnit]s.
*/
@@ -526,8 +599,9 @@
cachingPolicy: AST_CACHING_POLICY);
/**
- * The resolved [CompilationUnit] associated with a compilation unit, with
- * constants not yet resolved.
+ * The resolved [CompilationUnit] associated with a compilation unit in which
+ * the types of class members have been inferred in addition to everything that
+ * is true of a [RESOLVED_UNIT8].
*
* The result is only available for [LibrarySpecificUnit]s.
*/
@@ -603,10 +677,20 @@
'VERIFY_ERRORS', AnalysisError.NO_ERRORS);
/**
+ * Return a list of unique errors for the [Source] of the given [target].
+ */
+List<AnalysisError> getTargetSourceErrors(
+ RecordingErrorListener listener, AnalysisTarget target) {
+ Source source = target.source;
+ List<AnalysisError> errors = listener.getErrorsForSource(source);
+ return getUniqueErrors(errors);
+}
+
+/**
* Return a list of errors containing the errors from the given [errors] list
* but with duplications removed.
*/
-List<AnalysisError> removeDuplicateErrors(List<AnalysisError> errors) {
+List<AnalysisError> getUniqueErrors(List<AnalysisError> errors) {
if (errors.isEmpty) {
return errors;
}
@@ -1638,7 +1722,7 @@
'Cannot build inputs for a ${target.runtimeType}');
}
return <String, TaskInput>{
- 'resolvedUnit': RESOLVED_UNIT9
+ 'resolvedUnit': RESOLVED_UNIT10
.of(new LibrarySpecificUnit(librarySource, target.source)),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
};
@@ -1752,7 +1836,7 @@
* static variable whose type should be inferred.
*/
class ComputeInferableStaticVariableDependenciesTask
- extends ConstantEvaluationAnalysisTask {
+ extends InferStaticVariableTask {
/**
* The name of the [RESOLVED_UNIT5] input.
*/
@@ -1776,19 +1860,11 @@
//
// Prepare inputs.
//
- VariableElement variable = target;
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
//
// Compute dependencies.
//
- NodeLocator locator = new NodeLocator(variable.nameOffset);
- AstNode node = locator.searchWithin(unit);
- VariableDeclaration declaration =
- node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
- if (declaration == null || declaration.name != node) {
- throw new AnalysisException(
- "NodeLocator failed to find a variable's declaration");
- }
+ VariableDeclaration declaration = getDeclaration(unit);
VariableGatherer gatherer = new VariableGatherer(_isInferableStatic);
declaration.initializer.accept(gatherer);
//
@@ -1940,6 +2016,85 @@
}
/**
+ * A task that computes the [PROPAGABLE_VARIABLE_DEPENDENCIES] for a variable.
+ */
+class ComputePropagableVariableDependenciesTask
+ extends InferStaticVariableTask {
+ /**
+ * The name of the [RESOLVED_UNIT5] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ComputePropagableVariableDependenciesTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[PROPAGABLE_VARIABLE_DEPENDENCIES]);
+
+ ComputePropagableVariableDependenciesTask(
+ InternalAnalysisContext context, VariableElement variable)
+ : super(context, variable);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ //
+ // Compute dependencies.
+ //
+ VariableDeclaration declaration = getDeclaration(unit);
+ VariableGatherer gatherer = new VariableGatherer(_isPropagable);
+ declaration.initializer.accept(gatherer);
+ //
+ // Record outputs.
+ //
+ outputs[PROPAGABLE_VARIABLE_DEPENDENCIES] = gatherer.results.toList();
+ }
+
+ /**
+ * Return `true` if the given [variable] is a variable whose type can be
+ * propagated.
+ */
+ bool _isPropagable(VariableElement variable) =>
+ variable is PropertyInducingElement &&
+ (variable.isConst || variable.isFinal) &&
+ variable.hasImplicitType &&
+ variable.initializer != null;
+
+ /**
+ * 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 [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ if (target is VariableElement) {
+ CompilationUnitElementImpl unit = target
+ .getAncestor((Element element) => element is CompilationUnitElement);
+ return <String, TaskInput>{
+ UNIT_INPUT: RESOLVED_UNIT5
+ .of(new LibrarySpecificUnit(unit.librarySource, unit.source))
+ };
+ }
+ throw new AnalysisException(
+ 'Cannot build inputs for a ${target.runtimeType}');
+ }
+
+ /**
+ * Create a [ComputePropagableVariableDependenciesTask] based on the
+ * given [target] in the given [context].
+ */
+ static ComputePropagableVariableDependenciesTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ComputePropagableVariableDependenciesTask(context, target);
+ }
+}
+
+/**
* A base class for analysis tasks whose target is expected to be a
* [ConstantEvaluationTarget].
*/
@@ -2202,11 +2357,11 @@
}
/**
- * A task that builds [RESOLVED_UNIT10] for a unit.
+ * A task that builds [RESOLVED_UNIT11] for a unit.
*/
class EvaluateUnitConstantsTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT9] input.
+ * The name of the [RESOLVED_UNIT10] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2222,7 +2377,7 @@
'EvaluateUnitConstantsTask',
createTask,
buildInputs,
- <ResultDescriptor>[RESOLVED_UNIT10]);
+ <ResultDescriptor>[RESOLVED_UNIT11]);
EvaluateUnitConstantsTask(AnalysisContext context, LibrarySpecificUnit target)
: super(context, target);
@@ -2235,7 +2390,7 @@
// No actual work needs to be performed; the task manager will ensure that
// all constants are evaluated before this method is called.
CompilationUnit unit = getRequiredInput(UNIT_INPUT);
- outputs[RESOLVED_UNIT10] = unit;
+ outputs[RESOLVED_UNIT11] = unit;
}
/**
@@ -2247,7 +2402,7 @@
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
'libraryElement': LIBRARY_ELEMENT.of(unit.library),
- UNIT_INPUT: RESOLVED_UNIT9.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT10.of(unit),
CONSTANT_VALUES:
COMPILATION_UNIT_CONSTANTS.of(unit).toListOf(CONSTANT_VALUE)
};
@@ -2371,7 +2526,7 @@
*/
class GatherUsedImportedElementsTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT9] input.
+ * The name of the [RESOLVED_UNIT10] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2415,7 +2570,7 @@
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
- return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT9.of(unit)};
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT10.of(unit)};
}
/**
@@ -2433,7 +2588,7 @@
*/
class GatherUsedLocalElementsTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT9] input.
+ * The name of the [RESOLVED_UNIT10] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2477,7 +2632,7 @@
*/
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
- return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT9.of(unit)};
+ return <String, TaskInput>{UNIT_INPUT: RESOLVED_UNIT10.of(unit)};
}
/**
@@ -2495,7 +2650,7 @@
*/
class GenerateHintsTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT9] input.
+ * The name of the [RESOLVED_UNIT10] input.
*/
static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
@@ -2701,7 +2856,7 @@
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
/**
- * The name of the input whose value is the [RESOLVED_UNIT6] for the
+ * The name of the input whose value is the [RESOLVED_UNIT7] for the
* compilation unit.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2713,7 +2868,7 @@
'InferInstanceMembersInUnitTask',
createTask,
buildInputs,
- <ResultDescriptor>[RESOLVED_UNIT8]);
+ <ResultDescriptor>[RESOLVED_UNIT9]);
/**
* Initialize a newly created task to build a library element for the given
@@ -2744,7 +2899,7 @@
//
// Record outputs.
//
- outputs[RESOLVED_UNIT8] = unit;
+ outputs[RESOLVED_UNIT9] = unit;
}
/**
@@ -2755,7 +2910,7 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- UNIT_INPUT: RESOLVED_UNIT7.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT8.of(unit),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
// In strong mode, add additional dependencies to enforce inference
// ordering.
@@ -2763,12 +2918,12 @@
// Require that field re-resolution be complete for all units in the
// current library cycle.
'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT7
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
.of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
// Require that full inference be complete for all dependencies of the
// current library cycle.
'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
.of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
};
}
@@ -2798,13 +2953,13 @@
*/
VariableDeclaration getDeclaration(CompilationUnit unit) {
VariableElement variable = target;
- NodeLocator locator = new NodeLocator(variable.nameOffset);
- AstNode node = locator.searchWithin(unit);
+ AstNode node = new NodeLocator2(variable.nameOffset).searchWithin(unit);
VariableDeclaration declaration =
node.getAncestor((AstNode ancestor) => ancestor is VariableDeclaration);
if (declaration == null || declaration.name != node) {
throw new AnalysisException(
- "Failed to find the declaration of the variable ${variable.displayName} in ${variable.source}");
+ "Failed to find the declaration of the variable "
+ "${variable.displayName} in ${variable.source}");
}
return declaration;
}
@@ -2816,7 +2971,7 @@
*/
class InferStaticVariableTypesInUnitTask extends SourceBasedAnalysisTask {
/**
- * The name of the input whose value is the [RESOLVED_UNIT5] for the
+ * The name of the input whose value is the [RESOLVED_UNIT6] for the
* compilation unit.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -2834,7 +2989,7 @@
'InferStaticVariableTypesInUnitTask',
createTask,
buildInputs,
- <ResultDescriptor>[RESOLVED_UNIT6]);
+ <ResultDescriptor>[RESOLVED_UNIT7]);
/**
* Initialize a newly created task to build a library element for the given
@@ -2858,7 +3013,7 @@
// because the work has implicitly been done by virtue of the task model
// preparing all of the inputs.
//
- outputs[RESOLVED_UNIT6] = unit;
+ outputs[RESOLVED_UNIT7] = unit;
}
/**
@@ -2872,7 +3027,7 @@
INFERRED_VARIABLES_INPUT: INFERABLE_STATIC_VARIABLES_IN_UNIT
.of(unit)
.toListOf(INFERRED_STATIC_VARIABLE),
- UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+ UNIT_INPUT: RESOLVED_UNIT6.of(unit)
};
}
@@ -2903,7 +3058,7 @@
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
/**
- * The name of the [RESOLVED_UNIT5] input.
+ * The name of the [RESOLVED_UNIT6] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -3001,14 +3156,14 @@
.of(variable)
.toListOf(INFERRED_STATIC_VARIABLE),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
- UNIT_INPUT: RESOLVED_UNIT5.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT6.of(unit),
// In strong mode, add additional dependencies to enforce inference
// ordering.
// Require that full inference be complete for all dependencies of the
// current library cycle.
'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
.of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
};
}
@@ -3315,8 +3470,7 @@
List<Source> exportedSources = exportedSourceSet.toList();
List<Source> importedSources = importedSourceSet.toList();
List<Source> includedSources = includedSourceSet.toList();
- List<AnalysisError> parseErrors =
- removeDuplicateErrors(errorListener.errors);
+ List<AnalysisError> parseErrors = getUniqueErrors(errorListener.errors);
List<Source> unitSources = <Source>[source]..addAll(includedSourceSet);
List<LibrarySpecificUnit> librarySpecificUnits =
unitSources.map((s) => new LibrarySpecificUnit(source, s)).toList();
@@ -3334,13 +3488,13 @@
/**
* 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)
};
}
@@ -3418,8 +3572,11 @@
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
'PartiallyResolveUnitReferencesTask',
createTask,
- buildInputs,
- <ResultDescriptor>[INFERABLE_STATIC_VARIABLES_IN_UNIT, RESOLVED_UNIT5]);
+ buildInputs, <ResultDescriptor>[
+ INFERABLE_STATIC_VARIABLES_IN_UNIT,
+ PROPAGABLE_VARIABLES_IN_UNIT,
+ RESOLVED_UNIT5
+ ]);
PartiallyResolveUnitReferencesTask(
InternalAnalysisContext context, AnalysisTarget target)
@@ -3440,21 +3597,21 @@
//
// Resolve references and record outputs.
//
+ InheritanceManager inheritanceManager =
+ new InheritanceManager(libraryElement);
+ PartialResolverVisitor visitor = new PartialResolverVisitor(libraryElement,
+ unitElement.source, typeProvider, AnalysisErrorListener.NULL_LISTENER,
+ inheritanceManager: inheritanceManager);
+ unit.accept(visitor);
+ //
+ // Record outputs.
+ //
if (context.analysisOptions.strongMode) {
- InheritanceManager inheritanceManager =
- new InheritanceManager(libraryElement);
- PartialResolverVisitor visitor = new PartialResolverVisitor(
- libraryElement,
- unitElement.source,
- typeProvider,
- AnalysisErrorListener.NULL_LISTENER,
- inheritanceManager: inheritanceManager);
- unit.accept(visitor);
-
- outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.variablesAndFields;
+ outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = visitor.staticVariables;
} else {
- outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = [];
+ outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT] = VariableElement.EMPTY_LIST;
}
+ outputs[PROPAGABLE_VARIABLES_IN_UNIT] = visitor.propagableVariables;
outputs[RESOLVED_UNIT5] = unit;
}
@@ -3476,7 +3633,7 @@
// Require that full inference be complete for all dependencies of the
// current library cycle.
'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
.of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
};
}
@@ -3492,6 +3649,285 @@
}
/**
+ * An artificial task that does nothing except to force propagated types for
+ * all propagable variables in the import/export closure a library.
+ */
+class PropagateVariableTypesInLibraryClosureTask
+ extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT6] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'PropagateVariableTypesInLibraryClosureTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[LIBRARY_ELEMENT7]);
+
+ PropagateVariableTypesInLibraryClosureTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+ outputs[LIBRARY_ELEMENT7] = library;
+ }
+
+ /**
+ * 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 [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ 'readyForClosure': READY_LIBRARY_ELEMENT6.of(source),
+ LIBRARY_INPUT: LIBRARY_ELEMENT6.of(source),
+ };
+ }
+
+ /**
+ * Create a [PropagateVariableTypesInLibraryClosureTask] based on the given
+ * [target] in the given [context].
+ */
+ static PropagateVariableTypesInLibraryClosureTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new PropagateVariableTypesInLibraryClosureTask(context, target);
+ }
+}
+
+/**
+ * An artificial task that does nothing except to force propagated types for
+ * all propagable variables in the defining and part units of a library.
+ */
+class PropagateVariableTypesInLibraryTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the [LIBRARY_ELEMENT5] input.
+ */
+ static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'PropagateVariableTypesInLibraryTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[LIBRARY_ELEMENT6]);
+
+ PropagateVariableTypesInLibraryTask(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ LibraryElement library = getRequiredInput(LIBRARY_INPUT);
+ outputs[LIBRARY_ELEMENT6] = library;
+ }
+
+ /**
+ * 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 [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ 'propagatedVariableTypesInUnits':
+ LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT6),
+ LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
+ };
+ }
+
+ /**
+ * Create a [PropagateVariableTypesInLibraryTask] based on the given [target]
+ * in the given [context].
+ */
+ static PropagateVariableTypesInLibraryTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new PropagateVariableTypesInLibraryTask(context, target);
+ }
+}
+
+/**
+ * A task that ensures that all of the propagable variables in a compilation
+ * unit have had their type propagated.
+ */
+class PropagateVariableTypesInUnitTask extends SourceBasedAnalysisTask {
+ /**
+ * The name of the input whose value is the [RESOLVED_UNIT5] for the
+ * compilation unit.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ /**
+ * The task descriptor describing this kind of task.
+ */
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'PropagateVariableTypesInUnitTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[RESOLVED_UNIT6]);
+
+ PropagateVariableTypesInUnitTask(
+ InternalAnalysisContext context, LibrarySpecificUnit unit)
+ : super(context, unit);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+ //
+ // Record outputs. There is no additional work to be done at this time
+ // because the work has implicitly been done by virtue of the task model
+ // preparing all of the inputs.
+ //
+ outputs[RESOLVED_UNIT6] = unit;
+ }
+
+ /**
+ * 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
+ * [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ LibrarySpecificUnit unit = target;
+ return <String, TaskInput>{
+ 'variables':
+ PROPAGABLE_VARIABLES_IN_UNIT.of(unit).toListOf(PROPAGATED_VARIABLE),
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit)
+ };
+ }
+
+ /**
+ * Create a [PropagateVariableTypesInUnitTask] based on the given [target]
+ * in the given [context].
+ */
+ static PropagateVariableTypesInUnitTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new PropagateVariableTypesInUnitTask(context, target);
+ }
+}
+
+/**
+ * A task that computes the propagated type of an propagable variable and
+ * stores it in the element model.
+ */
+class PropagateVariableTypeTask extends InferStaticVariableTask {
+ /**
+ * The name of the [TYPE_PROVIDER] input.
+ */
+ static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+ /**
+ * The name of the [RESOLVED_UNIT5] input.
+ */
+ static const String UNIT_INPUT = 'UNIT_INPUT';
+
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'PropagateVariableTypeTask',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[PROPAGATED_VARIABLE]);
+
+ PropagateVariableTypeTask(
+ InternalAnalysisContext context, VariableElement variable)
+ : super(context, variable);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ bool get handlesDependencyCycles => true;
+
+ @override
+ void internalPerform() {
+ //
+ // Prepare inputs.
+ //
+ PropertyInducingElementImpl variable = target;
+ TypeProvider typeProvider = getRequiredInput(TYPE_PROVIDER_INPUT);
+ CompilationUnit unit = getRequiredInput(UNIT_INPUT);
+
+ // If we're not in a dependency cycle, and we have no type annotation,
+ // re-resolve the right hand side and do propagation.
+ if (dependencyCycle == null && variable.hasImplicitType) {
+ VariableDeclaration declaration = getDeclaration(unit);
+ //
+ // Re-resolve the variable's initializer with the propagated types of
+ // other variables.
+ //
+ Expression initializer = declaration.initializer;
+ ResolutionContext resolutionContext = ResolutionContextBuilder.contextFor(
+ initializer, AnalysisErrorListener.NULL_LISTENER);
+ ResolverVisitor visitor = new ResolverVisitor(variable.library,
+ variable.source, typeProvider, AnalysisErrorListener.NULL_LISTENER,
+ nameScope: resolutionContext.scope);
+ if (resolutionContext.enclosingClassDeclaration != null) {
+ visitor.prepareToResolveMembersInClass(
+ resolutionContext.enclosingClassDeclaration);
+ }
+ visitor.initForIncrementalResolution();
+ initializer.accept(visitor);
+ //
+ // Record the type of the variable.
+ //
+ DartType newType = initializer.bestType;
+ if (newType != null && !newType.isBottom && !newType.isDynamic) {
+ variable.propagatedType = newType;
+ }
+ }
+ //
+ // Record outputs.
+ //
+ outputs[PROPAGATED_VARIABLE] = variable;
+ }
+
+ /**
+ * 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
+ * [target].
+ */
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ VariableElement variable = target;
+ LibrarySpecificUnit unit =
+ new LibrarySpecificUnit(variable.library.source, variable.source);
+ return <String, TaskInput>{
+ 'dependencies': PROPAGABLE_VARIABLE_DEPENDENCIES
+ .of(variable)
+ .toListOf(PROPAGATED_VARIABLE),
+ TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
+ UNIT_INPUT: RESOLVED_UNIT5.of(unit),
+ };
+ }
+
+ /**
+ * Create a [PropagateVariableTypeTask] based on the given [target] in the
+ * given [context].
+ */
+ static PropagateVariableTypeTask createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new PropagateVariableTypeTask(context, target);
+ }
+}
+
+/**
* The helper for building the public [Namespace] of a [LibraryElement].
*/
class PublicNamespaceBuilder {
@@ -3617,6 +4053,49 @@
}
/**
+ * A task that ensures that [LIBRARY_ELEMENT6] is ready for the target library
+ * source and its import/export closure.
+ */
+class ReadyLibraryElement6Task extends SourceBasedAnalysisTask {
+ static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+ 'ReadyLibraryElement6Task',
+ createTask,
+ buildInputs,
+ <ResultDescriptor>[READY_LIBRARY_ELEMENT6]);
+
+ ReadyLibraryElement6Task(
+ InternalAnalysisContext context, AnalysisTarget target)
+ : super(context, target);
+
+ @override
+ TaskDescriptor get descriptor => DESCRIPTOR;
+
+ @override
+ bool get handlesDependencyCycles => true;
+
+ @override
+ void internalPerform() {
+ outputs[READY_LIBRARY_ELEMENT6] = true;
+ }
+
+ static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
+ Source source = target;
+ return <String, TaskInput>{
+ 'thisLibraryElementReady': LIBRARY_ELEMENT6.of(source),
+ 'directlyImportedLibrariesReady':
+ IMPORTED_LIBRARIES.of(source).toListOf(READY_LIBRARY_ELEMENT6),
+ 'directlyExportedLibrariesReady':
+ EXPORTED_LIBRARIES.of(source).toListOf(READY_LIBRARY_ELEMENT6),
+ };
+ }
+
+ static ReadyLibraryElement6Task createTask(
+ AnalysisContext context, AnalysisTarget target) {
+ return new ReadyLibraryElement6Task(context, target);
+ }
+}
+
+/**
* A task that ensures that [RESOLVED_UNIT10] is ready for every unit of the
* target library source and its import/export closure.
*/
@@ -3661,17 +4140,18 @@
}
/**
- * A task that ensures that [RESOLVED_UNIT9] is ready for every unit of the
+ * A task that ensures that [RESOLVED_UNIT11] is ready for every unit of the
* target library source and its import/export closure.
*/
-class ReadyResolvedUnit9Task extends SourceBasedAnalysisTask {
+class ReadyResolvedUnit11Task extends SourceBasedAnalysisTask {
static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
- 'ReadyResolvedUnit9Task',
+ 'ReadyResolvedUnit11Task',
createTask,
buildInputs,
- <ResultDescriptor>[READY_RESOLVED_UNIT9]);
+ <ResultDescriptor>[READY_RESOLVED_UNIT11]);
- ReadyResolvedUnit9Task(InternalAnalysisContext context, AnalysisTarget target)
+ ReadyResolvedUnit11Task(
+ InternalAnalysisContext context, AnalysisTarget target)
: super(context, target);
@override
@@ -3682,24 +4162,24 @@
@override
void internalPerform() {
- outputs[READY_RESOLVED_UNIT9] = true;
+ outputs[READY_RESOLVED_UNIT11] = true;
}
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
Source source = target;
return <String, TaskInput>{
'thisLibraryUnitsReady':
- LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT9),
+ LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT11),
'directlyImportedLibrariesReady':
- IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT9),
+ IMPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
'directlyExportedLibrariesReady':
- EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT9),
+ EXPORTED_LIBRARIES.of(source).toListOf(READY_RESOLVED_UNIT11),
};
}
- static ReadyResolvedUnit9Task createTask(
+ static ReadyResolvedUnit11Task createTask(
AnalysisContext context, AnalysisTarget target) {
- return new ReadyResolvedUnit9Task(context, target);
+ return new ReadyResolvedUnit11Task(context, target);
}
}
@@ -3860,7 +4340,7 @@
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
/**
- * The name of the input whose value is the [RESOLVED_UNIT6] for the
+ * The name of the input whose value is the [RESOLVED_UNIT7] for the
* compilation unit.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -3872,7 +4352,7 @@
'ResolveInstanceFieldsInUnitTask',
createTask,
buildInputs,
- <ResultDescriptor>[RESOLVED_UNIT7]);
+ <ResultDescriptor>[RESOLVED_UNIT8]);
/**
* Initialize a newly created task to build a library element for the given
@@ -3920,7 +4400,7 @@
//
// Record outputs.
//
- outputs[RESOLVED_UNIT7] = unit;
+ outputs[RESOLVED_UNIT8] = unit;
}
/**
@@ -3931,7 +4411,7 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- UNIT_INPUT: RESOLVED_UNIT6.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT7.of(unit),
LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
// In strong mode, add additional dependencies to enforce inference
@@ -3940,12 +4420,12 @@
// Require that static variable inference be complete for all units in
// the current library cycle.
'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT6
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT7
.of(new LibrarySpecificUnit(unit.librarySource, unit.source))),
// Require that full inference be complete for all dependencies of the
// current library cycle.
'orderLibraryCycles': LIBRARY_CYCLE_DEPENDENCIES.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
.of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
};
}
@@ -3961,7 +4441,7 @@
}
/**
- * A task that finishes resolution by requesting [RESOLVED_UNIT9] for every
+ * A task that finishes resolution by requesting [RESOLVED_UNIT10] for every
* unit in the libraries closure and produces [LIBRARY_ELEMENT].
*/
class ResolveLibraryReferencesTask extends SourceBasedAnalysisTask {
@@ -3971,7 +4451,7 @@
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
/**
- * The name of the list of [RESOLVED_UNIT9] input.
+ * The name of the list of [RESOLVED_UNIT10] input.
*/
static const String UNITS_INPUT = 'UNITS_INPUT';
@@ -4019,8 +4499,8 @@
Source source = target;
return <String, TaskInput>{
LIBRARY_INPUT: LIBRARY_ELEMENT5.of(source),
- UNITS_INPUT: LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT9),
- 'thisLibraryClosureIsReady': READY_RESOLVED_UNIT9.of(source),
+ UNITS_INPUT: LIBRARY_SPECIFIC_UNITS.of(source).toListOf(RESOLVED_UNIT10),
+ 'thisLibraryClosureIsReady': READY_RESOLVED_UNIT10.of(source),
};
}
@@ -4113,7 +4593,7 @@
*/
class ResolveUnitTask extends SourceBasedAnalysisTask {
/**
- * The name of the input whose value is the defining [LIBRARY_ELEMENT5].
+ * The name of the input whose value is the defining [LIBRARY_ELEMENT7].
*/
static const String LIBRARY_INPUT = 'LIBRARY_INPUT';
@@ -4123,7 +4603,7 @@
static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
/**
- * The name of the [RESOLVED_UNIT8] input.
+ * The name of the [RESOLVED_UNIT9] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -4131,7 +4611,7 @@
'ResolveUnitTask',
createTask,
buildInputs,
- <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT9]);
+ <ResultDescriptor>[RESOLVE_UNIT_ERRORS, RESOLVED_UNIT10]);
ResolveUnitTask(
InternalAnalysisContext context, LibrarySpecificUnit compilationUnit)
@@ -4163,8 +4643,8 @@
// AST's for constructor initializers into it) but does not produce an
// updated version of the element model.
//
- outputs[RESOLVE_UNIT_ERRORS] = errorListener.errors;
- outputs[RESOLVED_UNIT9] = unit;
+ outputs[RESOLVE_UNIT_ERRORS] = getTargetSourceErrors(errorListener, target);
+ outputs[RESOLVED_UNIT10] = unit;
}
/**
@@ -4175,16 +4655,16 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- LIBRARY_INPUT: LIBRARY_ELEMENT5.of(unit.library),
+ LIBRARY_INPUT: LIBRARY_ELEMENT7.of(unit.library),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
- UNIT_INPUT: RESOLVED_UNIT8.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT9.of(unit),
// In strong mode, add additional dependencies to enforce inference
// ordering.
// Require that inference be complete for all units in the
// current library cycle.
'orderLibraryCycleTasks': LIBRARY_CYCLE_UNITS.of(unit).toList(
- (CompilationUnitElementImpl unit) => RESOLVED_UNIT8
+ (CompilationUnitElementImpl unit) => RESOLVED_UNIT9
.of(new LibrarySpecificUnit(unit.librarySource, unit.source)))
};
}
@@ -4254,7 +4734,7 @@
// Record outputs.
//
outputs[RESOLVE_TYPE_NAMES_ERRORS] =
- removeDuplicateErrors(errorListener.errors);
+ getTargetSourceErrors(errorListener, target);
outputs[RESOLVED_UNIT3] = unit;
}
@@ -4345,7 +4825,7 @@
//
outputs[RESOLVED_UNIT4] = unit;
outputs[VARIABLE_REFERENCE_ERRORS] =
- removeDuplicateErrors(errorListener.errors);
+ getTargetSourceErrors(errorListener, target);
}
/**
@@ -4442,7 +4922,7 @@
outputs[TOKEN_STREAM] = scanner.tokenize();
outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
- outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
} else if (target is Source) {
String content = getRequiredInput(CONTENT_INPUT_NAME);
@@ -4453,7 +4933,7 @@
outputs[TOKEN_STREAM] = scanner.tokenize();
outputs[LINE_INFO] = new LineInfo(scanner.lineStarts);
- outputs[SCAN_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ outputs[SCAN_ERRORS] = getUniqueErrors(errorListener.errors);
} else {
throw new AnalysisException(
'Cannot scan Dart code from a ${target.runtimeType}');
@@ -4493,7 +4973,7 @@
*/
class StrongModeVerifyUnitTask extends SourceBasedAnalysisTask {
/**
- * The name of the [RESOLVED_UNIT10] input.
+ * The name of the [RESOLVED_UNIT11] input.
*/
static const String UNIT_INPUT = 'UNIT_INPUT';
@@ -4533,7 +5013,7 @@
//
// Record outputs.
//
- outputs[STRONG_MODE_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ outputs[STRONG_MODE_ERRORS] = getUniqueErrors(errorListener.errors);
outputs[RESOLVED_UNIT] = unit;
}
@@ -4545,9 +5025,9 @@
static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
LibrarySpecificUnit unit = target;
return <String, TaskInput>{
- UNIT_INPUT: RESOLVED_UNIT10.of(unit),
+ UNIT_INPUT: RESOLVED_UNIT11.of(unit),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request),
- 'thisLibraryClosureIsReady': READY_RESOLVED_UNIT10.of(unit.library),
+ 'thisLibraryClosureIsReady': READY_RESOLVED_UNIT11.of(unit.library),
};
}
@@ -4628,7 +5108,7 @@
//
// Record outputs.
//
- outputs[VERIFY_ERRORS] = removeDuplicateErrors(errorListener.errors);
+ outputs[VERIFY_ERRORS] = getUniqueErrors(errorListener.errors);
}
/**
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index 45faf41..0596490 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/src/task/strong/info.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/model.dart';
import 'package:source_span/source_span.dart';
@@ -125,6 +126,10 @@
new List.from(AnalyzerOptions.ignoreSynonyms)
..addAll(AnalyzerOptions.includeSynonyms));
+ bool recognizedErrorCode(String name) =>
+ ErrorCode.values.any((ErrorCode code) => code.name == name) ||
+ StaticInfo.names.contains(name);
+
@override
void validate(ErrorReporter reporter, Map<String, YamlNode> options) {
var analyzer = options[AnalyzerOptions.analyzer];
@@ -138,7 +143,7 @@
filters.nodes.forEach((k, v) {
if (k is YamlScalar) {
value = toUpperCase(k.value);
- if (!ErrorCode.values.any((ErrorCode code) => code.name == value)) {
+ if (!recognizedErrorCode(value)) {
reporter.reportErrorForSpan(
AnalysisOptionsWarningCode.UNRECOGNIZED_ERROR_CODE,
k.span,
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 5a6bcaa..d557eb2 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -467,6 +467,10 @@
if (node.typeArguments != null) {
var targs = node.typeArguments.arguments;
if (targs.length > 0) type = targs[0].type;
+ } else if (node.staticType is InterfaceType) {
+ InterfaceType listT = node.staticType;
+ var targs = listT.typeArguments;
+ if (targs != null && targs.length > 0) type = targs[0];
}
var elements = node.elements;
for (int i = 0; i < elements.length; i++) {
@@ -483,6 +487,13 @@
var targs = node.typeArguments.arguments;
if (targs.length > 0) ktype = targs[0].type;
if (targs.length > 1) vtype = targs[1].type;
+ } else if (node.staticType is InterfaceType) {
+ InterfaceType mapT = node.staticType;
+ var targs = mapT.typeArguments;
+ if (targs != null) {
+ if (targs.length > 0) ktype = targs[0];
+ if (targs.length > 1) vtype = targs[1];
+ }
}
var entries = node.entries;
for (int i = 0; i < entries.length; i++) {
@@ -572,8 +583,13 @@
@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);
}
@@ -597,6 +613,14 @@
// analyzer error in this case.
return;
}
+ InterfaceType futureType = rules.provider.futureType;
+ DartType actualType = expression.staticType;
+ if (body.isAsynchronous &&
+ !body.isGenerator &&
+ actualType is InterfaceType &&
+ actualType.element == futureType.element) {
+ type = futureType.substitute4([type]);
+ }
// TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
if (expression != null) checkAssignment(expression, type);
}
@@ -947,7 +971,6 @@
void _recordMessage(StaticInfo info) {
if (info == null) return;
var error = info.toAnalysisError();
-
var severity = error.errorCode.errorSeverity;
if (severity == ErrorSeverity.ERROR) _failure = true;
if (severity != ErrorSeverity.INFO || _hints) {
diff --git a/pkg/analyzer/lib/src/task/strong/info.dart b/pkg/analyzer/lib/src/task/strong/info.dart
index 9d4812f..dbdc4e0 100644
--- a/pkg/analyzer/lib/src/task/strong/info.dart
+++ b/pkg/analyzer/lib/src/task/strong/info.dart
@@ -14,6 +14,25 @@
import 'rules.dart';
+// A down cast due to a variable declaration to a ground type. E.g.,
+// T x = expr;
+// where T is ground. We exclude non-ground types as these behave differently
+// compared to standard Dart.
+class AssignmentCast extends DownCast {
+ AssignmentCast(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ @override
+ String get name => 'STRONG_MODE_ASSIGNMENT_CAST';
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+// Coercion which casts one type to another
+class Cast extends Coercion {
+ Cast(DartType fromType, DartType toType) : super(fromType, toType);
+}
+
// The abstract type of coercions mapping one type to another.
// This class also exposes static builder functions which
// check for errors and reduce redundant coercions to the identity.
@@ -22,18 +41,8 @@
final DartType toType;
Coercion(this.fromType, this.toType);
static Coercion cast(DartType fromT, DartType toT) => new Cast(fromT, toT);
- static Coercion identity(DartType type) => new Identity(type);
static Coercion error() => new CoercionError();
-}
-
-// Coercion which casts one type to another
-class Cast extends Coercion {
- Cast(DartType fromType, DartType toType) : super(fromType, toType);
-}
-
-// The identity coercion
-class Identity extends Coercion {
- Identity(DartType fromType) : super(fromType, fromType);
+ static Coercion identity(DartType type) => new Identity(type);
}
// The error coercion. This coercion signals that a coercion
@@ -43,50 +52,23 @@
CoercionError() : super(null, null);
}
-// TODO(jmesserly): this could use some refactoring. These are essentially
-// like ErrorCodes in analyzer, but we're including some details in our message.
-// Analyzer instead has template strings, and replaces '{0}' with the first
-// argument.
-abstract class StaticInfo {
- /// AST Node this info is attached to.
- AstNode get node;
-
- // TODO(jmesserly): review the usage of error codes. We probably want our own,
- // as well as some DDC specific [ErrorType]s.
- ErrorCode toErrorCode();
-
- // TODO(jmesserly): what convention to use here?
- String get name => 'dev_compiler.$runtimeType';
-
- List<Object> get arguments => [node];
-
- AnalysisError toAnalysisError() {
- int begin = node is AnnotatedNode
- ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
- : node.offset;
- int length = node.end - begin;
- var source = (node.root as CompilationUnit).element.source;
- return new AnalysisError(source, begin, length, toErrorCode(), arguments);
- }
-}
-
/// Implicitly injected expression conversion.
abstract class CoercionInfo extends StaticInfo {
+ static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+
final TypeRules rules;
final Expression node;
- DartType get convertedType;
-
CoercionInfo(this.rules, this.node);
DartType get baseType => rules.getStaticType(node);
- DartType get staticType => convertedType;
+ DartType get convertedType;
String get message;
- toErrorCode() => new HintCode(name, message);
+ DartType get staticType => convertedType;
- static const String _propertyName = 'dev_compiler.src.info.CoercionInfo';
+ toErrorCode() => new HintCode(name, message);
/// Gets the coercion info associated with this node.
static CoercionInfo get(AstNode node) => node.getProperty(_propertyName);
@@ -112,11 +94,11 @@
baseType.isAssignableTo(_cast.toType)));
}
+ @override List<Object> get arguments => [node, baseType, convertedType];
+
Cast get cast => _cast;
DartType get convertedType => _cast.toType;
-
- @override List<Object> get arguments => [node, baseType, convertedType];
@override String get message => '{0} ({1}) will need runtime check '
'to cast to type {2}';
@@ -195,55 +177,17 @@
}
//
-// Standard down casts. These casts are implicitly injected by the compiler.
-//
-
-// A down cast from dynamic to T.
-class DynamicCast extends DownCast {
- DynamicCast(TypeRules rules, Expression expression, Cast cast)
- : super._internal(rules, expression, cast);
-
- toErrorCode() => new HintCode(name, message);
-}
-
-// A down cast due to a variable declaration to a ground type. E.g.,
-// T x = expr;
-// where T is ground. We exclude non-ground types as these behave differently
-// compared to standard Dart.
-class AssignmentCast extends DownCast {
- AssignmentCast(TypeRules rules, Expression expression, Cast cast)
- : super._internal(rules, expression, cast);
-
- toErrorCode() => new HintCode(name, message);
-}
-
-//
-// Temporary "casts" of allocation sites - literals, constructor invocations,
-// and closures. These should be handled by contextual inference. In most
-// cases, inference will be sufficient, though in some it may unmask an actual
-// error: e.g.,
-// List<int> l = [1, 2, 3]; // Inference succeeds
-// List<String> l = [1, 2, 3]; // Inference reveals static type error
-// We're marking all as warnings for now.
-//
-// TODO(vsm,leafp): Remove this.
-class UninferredClosure extends DownCast {
- UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
- : super._internal(rules, expression, cast);
-
- toErrorCode() => new StaticTypeWarningCode(name, message);
-}
-
-//
// Implicit down casts. These are only injected by the compiler by flag.
//
-
// A down cast to a non-ground type. These behave differently from standard
// Dart and may be more likely to fail at runtime.
class DownCastComposite extends DownCast {
DownCastComposite(TypeRules rules, Expression expression, Cast cast)
: super._internal(rules, expression, cast);
+ @override
+ String get name => 'STRONG_MODE_DOWN_CAST_COMPOSITE';
+
toErrorCode() => new StaticTypeWarningCode(name, message);
}
@@ -253,30 +197,64 @@
DownCastImplicit(TypeRules rules, Expression expression, Cast cast)
: super._internal(rules, expression, cast);
+ @override
+ String get name => 'STRONG_MODE_DOWN_CAST_IMPLICIT';
+
toErrorCode() => new HintCode(name, message);
}
-// An inferred type for the wrapped expression, which may need to be
-// reified into the term
-abstract class InferredTypeBase extends CoercionInfo {
- final DartType _type;
+// A down cast from dynamic to T.
+class DynamicCast extends DownCast {
+ DynamicCast(TypeRules rules, Expression expression, Cast cast)
+ : super._internal(rules, expression, cast);
- InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
- : super(rules, expression);
-
- DartType get type => _type;
- DartType get convertedType => type;
- @override String get message => '{0} has inferred type {1}';
- @override List get arguments => [node, type];
+ @override
+ String get name => 'STRONG_MODE_DYNAMIC_CAST';
toErrorCode() => new HintCode(name, message);
}
+class DynamicInvoke extends CoercionInfo {
+ static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
+
+ DynamicInvoke(TypeRules rules, Expression expression)
+ : super(rules, expression);
+ DartType get convertedType => rules.provider.dynamicType;
+ String get message => '{0} requires dynamic invoke';
+
+ @override
+ String get name => 'STRONG_MODE_DYNAMIC_INVOKE';
+
+ toErrorCode() => new HintCode(name, message);
+
+ /// Whether this [node] is the target of a dynamic operation.
+ static bool get(AstNode node) {
+ var value = node.getProperty(_propertyName);
+ return value != null ? value : false;
+ }
+
+ /// Sets whether this node is the target of a dynamic operation.
+ static bool set(AstNode node, bool value) {
+ // Free the storage for things that aren't dynamic.
+ if (value == false) value = null;
+ node.setProperty(_propertyName, value);
+ return value;
+ }
+}
+
+// The identity coercion
+class Identity extends Coercion {
+ Identity(DartType fromType) : super(fromType, fromType);
+}
+
// Standard / unspecialized inferred type
class InferredType extends InferredTypeBase {
InferredType(TypeRules rules, Expression expression, DartType type)
: super._internal(rules, expression, type);
+ @override
+ String get name => 'STRONG_MODE_INFERRED_TYPE';
+
// Factory to create correct InferredType variant.
static InferredTypeBase create(
TypeRules rules, Expression expression, DartType type) {
@@ -294,110 +272,72 @@
}
}
-// An infered type for a literal expression.
-class InferredTypeLiteral extends InferredTypeBase {
- InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
- : super._internal(rules, expression, type);
-}
-
// An inferred type for a non-literal allocation site.
class InferredTypeAllocation extends InferredTypeBase {
InferredTypeAllocation(TypeRules rules, Expression expression, DartType type)
: super._internal(rules, expression, type);
+
+ @override
+ String get name => 'STRONG_MODE_INFERRED_TYPE_ALLOCATION';
+}
+
+// An inferred type for the wrapped expression, which may need to be
+// reified into the term
+abstract class InferredTypeBase extends CoercionInfo {
+ final DartType _type;
+
+ InferredTypeBase._internal(TypeRules rules, Expression expression, this._type)
+ : super(rules, expression);
+
+ @override List get arguments => [node, type];
+ DartType get convertedType => type;
+ @override String get message => '{0} has inferred type {1}';
+ DartType get type => _type;
+
+ toErrorCode() => new HintCode(name, message);
}
// An inferred type for a closure expression
class InferredTypeClosure extends InferredTypeBase {
InferredTypeClosure(TypeRules rules, Expression expression, DartType type)
: super._internal(rules, expression, type);
+
+ @override
+ String get name => 'STRONG_MODE_INFERRED_TYPE_CLOSURE';
}
-class DynamicInvoke extends CoercionInfo {
- DynamicInvoke(TypeRules rules, Expression expression)
- : super(rules, expression);
+// An inferred type for a literal expression.
+class InferredTypeLiteral extends InferredTypeBase {
+ InferredTypeLiteral(TypeRules rules, Expression expression, DartType type)
+ : super._internal(rules, expression, type);
- DartType get convertedType => rules.provider.dynamicType;
- String get message => '{0} requires dynamic invoke';
- toErrorCode() => new HintCode(name, message);
-
- static const String _propertyName = 'dev_compiler.src.info.DynamicInvoke';
-
- /// Whether this [node] is the target of a dynamic operation.
- static bool get(AstNode node) {
- var value = node.getProperty(_propertyName);
- return value != null ? value : false;
- }
-
- /// Sets whether this node is the target of a dynamic operation.
- static bool set(AstNode node, bool value) {
- // Free the storage for things that aren't dynamic.
- if (value == false) value = null;
- node.setProperty(_propertyName, value);
- return value;
- }
+ @override
+ String get name => 'STRONG_MODE_INFERRED_TYPE_LITERAL';
}
-abstract class StaticError extends StaticInfo {
- final AstNode node;
+class InvalidFieldOverride extends InvalidOverride {
+ InvalidFieldOverride(AstNode node, ExecutableElement element,
+ InterfaceType base, DartType subType, DartType baseType)
+ : super(node, element, base, subType, baseType);
- StaticError(this.node);
+ String get message => 'Field declaration {3}.{1} cannot be '
+ 'overridden in {0}.';
- String get message;
-
- toErrorCode() => new CompileTimeErrorCode(name, message);
+ @override
+ String get name => 'STRONG_MODE_INVALID_FIELD_OVERRIDE';
}
-class StaticTypeError extends StaticError {
- final DartType baseType;
- final DartType expectedType;
- String reason = null;
+// Invalid override due to incompatible type. I.e., the overridden signature
+// is not compatible with the original.
+class InvalidMethodOverride extends InvalidOverride {
+ InvalidMethodOverride(AstNode node, ExecutableElement element,
+ InterfaceType base, FunctionType subType, FunctionType baseType)
+ : super(node, element, base, subType, baseType);
- StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
- {this.reason})
- : baseType = rules.getStaticType(expression),
- super(expression);
+ String get message => _messageHelper('Invalid override');
- @override List<Object> get arguments => [node, baseType, expectedType];
- @override String get message =>
- 'Type check failed: {0} ({1}) is not of type {2}' +
- ((reason == null) ? '' : ' because $reason');
-}
-
-class InvalidVariableDeclaration extends StaticError {
- final DartType expectedType;
-
- InvalidVariableDeclaration(
- TypeRules rules, AstNode declaration, this.expectedType)
- : super(declaration);
-
- @override List<Object> get arguments => [expectedType];
- @override String get message => 'Type check failed: null is not of type {0}';
-}
-
-class InvalidParameterDeclaration extends StaticError {
- final DartType expectedType;
-
- InvalidParameterDeclaration(
- TypeRules rules, FormalParameter declaration, this.expectedType)
- : super(declaration);
-
- @override List<Object> get arguments => [node, expectedType];
- @override String get message => 'Type check failed: {0} is not of type {1}';
-}
-
-class NonGroundTypeCheckInfo extends StaticInfo {
- final DartType type;
- final AstNode node;
-
- NonGroundTypeCheckInfo(this.node, this.type) {
- assert(node is IsExpression || node is AsExpression);
- }
-
- @override List<Object> get arguments => [type];
- String get message =>
- "Runtime check on non-ground type {0} may throw StrongModeError";
-
- toErrorCode() => new HintCode(name, message);
+ @override
+ String get name => 'STRONG_MODE_INVALID_METHOD_OVERRIDE';
}
// Invalid override of an instance member of a class.
@@ -427,11 +367,11 @@
fromMixin = node.parent is WithClause,
super(node);
- ClassElement get parent => element.enclosingElement;
-
@override List<Object> get arguments =>
[parent.name, element.name, subType, base, baseType];
+ ClassElement get parent => element.enclosingElement;
+
String _messageHelper(String errorName) {
var lcErrorName = errorName.toLowerCase();
var intro = fromBaseClass
@@ -442,23 +382,17 @@
}
}
-// Invalid override due to incompatible type. I.e., the overridden signature
-// is not compatible with the original.
-class InvalidMethodOverride extends InvalidOverride {
- InvalidMethodOverride(AstNode node, ExecutableElement element,
- InterfaceType base, FunctionType subType, FunctionType baseType)
- : super(node, element, base, subType, baseType);
+class InvalidParameterDeclaration extends StaticError {
+ final DartType expectedType;
- String get message => _messageHelper('Invalid override');
-}
+ InvalidParameterDeclaration(
+ TypeRules rules, FormalParameter declaration, this.expectedType)
+ : super(declaration);
-class InvalidFieldOverride extends InvalidOverride {
- InvalidFieldOverride(AstNode node, ExecutableElement element,
- InterfaceType base, DartType subType, DartType baseType)
- : super(node, element, base, subType, baseType);
-
- String get message => 'Field declaration {3}.{1} cannot be '
- 'overridden in {0}.';
+ @override List<Object> get arguments => [node, expectedType];
+ @override String get message => 'Type check failed: {0} is not of type {1}';
+ @override
+ String get name => 'STRONG_MODE_INVALID_PARAMETER_DECLARATION';
}
/// Dart constructors have one weird quirk, illustrated with this example:
@@ -495,4 +429,140 @@
@override String get message => "super call must be last in an initializer "
"list (see http://goo.gl/q1T4BB): {0}";
+
+ @override
+ String get name => 'STRONG_MODE_INVALID_SUPER_INVOCATION';
+}
+
+class InvalidVariableDeclaration extends StaticError {
+ final DartType expectedType;
+
+ InvalidVariableDeclaration(
+ TypeRules rules, AstNode declaration, this.expectedType)
+ : super(declaration);
+
+ @override List<Object> get arguments => [expectedType];
+ @override String get message => 'Type check failed: null is not of type {0}';
+
+ @override
+ String get name => 'STRONG_MODE_INVALID_VARIABLE_DECLARATION';
+}
+
+class NonGroundTypeCheckInfo extends StaticInfo {
+ final DartType type;
+ final AstNode node;
+
+ NonGroundTypeCheckInfo(this.node, this.type) {
+ assert(node is IsExpression || node is AsExpression);
+ }
+
+ @override List<Object> get arguments => [type];
+ String get message =>
+ "Runtime check on non-ground type {0} may throw StrongModeError";
+
+ @override
+ String get name => 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO';
+
+ toErrorCode() => new HintCode(name, message);
+}
+
+abstract class StaticError extends StaticInfo {
+ final AstNode node;
+
+ StaticError(this.node);
+
+ String get message;
+
+ toErrorCode() => new CompileTimeErrorCode(name, message);
+}
+
+// TODO(jmesserly): this could use some refactoring. These are essentially
+// like ErrorCodes in analyzer, but we're including some details in our message.
+// Analyzer instead has template strings, and replaces '{0}' with the first
+// argument.
+abstract class StaticInfo {
+ /// Strong-mode error code names.
+ ///
+ /// Used for error code configuration validation in `.analysis_options`.
+ static const List<String> names = const [
+ //
+ // Manually populated.
+ //
+ 'STRONG_MODE_ASSIGNMENT_CAST',
+ 'STRONG_MODE_DOWN_CAST_COMPOSITE',
+ 'STRONG_MODE_DOWN_CAST_IMPLICIT',
+ 'STRONG_MODE_DYNAMIC_CAST',
+ 'STRONG_MODE_DYNAMIC_INVOKE',
+ 'STRONG_MODE_INFERRED_TYPE',
+ 'STRONG_MODE_INFERRED_TYPE_ALLOCATION',
+ 'STRONG_MODE_INFERRED_TYPE_CLOSURE',
+ 'STRONG_MODE_INFERRED_TYPE_LITERAL',
+ 'STRONG_MODE_INVALID_FIELD_OVERRIDE',
+ 'STRONG_MODE_INVALID_METHOD_OVERRIDE',
+ 'STRONG_MODE_INVALID_PARAMETER_DECLARATION',
+ 'STRONG_MODE_INVALID_SUPER_INVOCATION',
+ 'STRONG_MODE_INVALID_VARIABLE_DECLARATION',
+ 'STRONG_MODE_NON_GROUND_TYPE_CHECK_INFO',
+ 'STRONG_MODE_STATIC_TYPE_ERROR',
+ 'STRONG_MODE_UNINFERRED_CLOSURE',
+ ];
+
+ List<Object> get arguments => [node];
+
+ String get name;
+
+ /// AST Node this info is attached to.
+ AstNode get node;
+
+ AnalysisError toAnalysisError() {
+ int begin = node is AnnotatedNode
+ ? (node as AnnotatedNode).firstTokenAfterCommentAndMetadata.offset
+ : node.offset;
+ int length = node.end - begin;
+ var source = (node.root as CompilationUnit).element.source;
+ return new AnalysisError(source, begin, length, toErrorCode(), arguments);
+ }
+
+ // TODO(jmesserly): review the usage of error codes. We probably want our own,
+ // as well as some DDC specific [ErrorType]s.
+ ErrorCode toErrorCode();
+}
+
+class StaticTypeError extends StaticError {
+ final DartType baseType;
+ final DartType expectedType;
+ String reason = null;
+
+ StaticTypeError(TypeRules rules, Expression expression, this.expectedType,
+ {this.reason})
+ : baseType = rules.getStaticType(expression),
+ super(expression);
+
+ @override List<Object> get arguments => [node, baseType, expectedType];
+ @override String get message =>
+ 'Type check failed: {0} ({1}) is not of type {2}' +
+ ((reason == null) ? '' : ' because $reason');
+
+ @override
+ String get name => 'STRONG_MODE_STATIC_TYPE_ERROR';
+}
+
+//
+// Temporary "casts" of allocation sites - literals, constructor invocations,
+// and closures. These should be handled by contextual inference. In most
+// cases, inference will be sufficient, though in some it may unmask an actual
+// error: e.g.,
+// List<int> l = [1, 2, 3]; // Inference succeeds
+// List<String> l = [1, 2, 3]; // Inference reveals static type error
+// We're marking all as warnings for now.
+//
+// TODO(vsm,leafp): Remove this.
+class UninferredClosure extends DownCast {
+ UninferredClosure(TypeRules rules, FunctionExpression expression, Cast cast)
+ : super._internal(rules, expression, cast);
+
+ @override
+ String get name => 'STRONG_MODE_UNINFERRED_CLOSURE';
+
+ toErrorCode() => new StaticTypeWarningCode(name, message);
}
diff --git a/pkg/analyzer/lib/src/task/strong/rules.dart b/pkg/analyzer/lib/src/task/strong/rules.dart
index 32236a8..909a6fb 100644
--- a/pkg/analyzer/lib/src/task/strong/rules.dart
+++ b/pkg/analyzer/lib/src/task/strong/rules.dart
@@ -321,6 +321,10 @@
return false;
}
+ if (t1.isVoid || t2.isVoid) {
+ return false;
+ }
+
if (t2.isDartCoreFunction) {
if (t1 is FunctionType) return true;
if (t1.element is ClassElement) {
@@ -421,6 +425,7 @@
var reason = null;
var errors = <String>[];
+
var ok = inferrer.inferExpression(expr, toT, errors);
if (ok) return InferredType.create(this, expr, toT);
reason = (errors.isNotEmpty) ? errors.first : null;
@@ -508,264 +513,12 @@
/// Downward inference
bool _inferExpression(Expression e, DartType t, List<String> errors,
{cast: true}) {
- if (e is ConditionalExpression) {
- return _inferConditionalExpression(e, t, errors);
- }
- if (e is ParenthesizedExpression) {
- return _inferParenthesizedExpression(e, t, errors);
- }
if (rules.isSubTypeOf(rules.getStaticType(e), t)) return true;
if (cast && rules.getStaticType(e).isDynamic) {
annotateCastFromDynamic(e, t);
return true;
}
- if (e is FunctionExpression) return _inferFunctionExpression(e, t, errors);
- if (e is ListLiteral) return _inferListLiteral(e, t, errors);
- if (e is MapLiteral) return _inferMapLiteral(e, t, errors);
- if (e is NamedExpression) return _inferNamedExpression(e, t, errors);
- if (e is InstanceCreationExpression) {
- return _inferInstanceCreationExpression(e, t, errors);
- }
errors.add("$e cannot be typed as $t");
return false;
}
-
- /// If t1 = I<dynamic, ..., dynamic>, then look for a supertype
- /// of t1 of the form K<S0, ..., Sm> where t2 = K<S0', ..., Sm'>
- /// If the supertype exists, use the constraints S0 <: S0', ... Sm <: Sm'
- /// to derive a concrete instantation for I of the form <T0, ..., Tn>,
- /// such that I<T0, .., Tn> <: t2
- List<DartType> _matchTypes(InterfaceType t1, InterfaceType t2) {
- if (t1 == t2) return t2.typeArguments;
- var tArgs1 = t1.typeArguments;
- var tArgs2 = t2.typeArguments;
- // If t1 isn't a raw type, bail out
- if (tArgs1 != null && tArgs1.any((t) => !t.isDynamic)) return null;
-
- // This is our inferred type argument list. We start at all dynamic,
- // and fill in with inferred types when we reach a match.
- var actuals =
- new List<DartType>.filled(tArgs1.length, rules.provider.dynamicType);
-
- // When we find the supertype of t1 with the same
- // classname as t2 (see below), we have the following:
- // If t1 is an instantiation of a class T1<X0, ..., Xn>
- // and t2 is an instantiation of a class T2<Y0, ...., Ym>
- // of the form t2 = T2<S0, ..., Sm>
- // then we want to choose instantiations for the Xi
- // T0, ..., Tn such that T1<T0, ..., Tn> <: t2 .
- // To find this, we simply instantate T1 with
- // X0, ..., Xn, and then find its superclass
- // T2<T0', ..., Tn'>. We then solve the constraint
- // set T0' <: S0, ..., Tn' <: Sn for the Xi.
- // Currently, we only handle constraints where
- // the Ti' is one of the Xi'. If there are multiple
- // constraints on some Xi, we choose the lower of the
- // two (if it exists).
- bool permute(List<DartType> permutedArgs) {
- if (permutedArgs == null) return false;
- var ps = t1.typeParameters;
- var ts = ps.map((p) => p.type).toList();
- for (int i = 0; i < permutedArgs.length; i++) {
- var tVar = permutedArgs[i];
- var tActual = tArgs2[i];
- var index = ts.indexOf(tVar);
- if (index >= 0 && rules.isSubTypeOf(tActual, actuals[index])) {
- actuals[index] = tActual;
- }
- }
- return actuals.any((x) => !x.isDynamic);
- }
-
- // Look for the first supertype of t1 with the same class name as t2.
- bool match(InterfaceType t1) {
- if (t1.element == t2.element) {
- return permute(t1.typeArguments);
- }
-
- if (t1 == rules.provider.objectType) return false;
-
- if (match(t1.superclass)) return true;
-
- for (final parent in t1.interfaces) {
- if (match(parent)) return true;
- }
-
- for (final parent in t1.mixins) {
- if (match(parent)) return true;
- }
- return false;
- }
-
- // We have that t1 = T1<dynamic, ..., dynamic>.
- // To match t1 against t2, we use the uninstantiated version
- // of t1, essentially treating it as an instantiation with
- // fresh variables, and solve for the variables.
- // t1.element.type will be of the form T1<X0, ..., Xn>
- if (!match(t1.element.type)) return null;
- var newT1 = t1.element.type.substitute4(actuals);
- // If we found a solution, return it.
- if (rules.isSubTypeOf(newT1, t2)) return actuals;
- return null;
- }
-
- /// These assume that e is not already a subtype of t
-
- bool _inferConditionalExpression(
- ConditionalExpression e, DartType t, errors) {
- return _inferExpression(e.thenExpression, t, errors) &&
- _inferExpression(e.elseExpression, t, errors);
- }
-
- bool _inferParenthesizedExpression(
- ParenthesizedExpression e, DartType t, errors) {
- return _inferExpression(e.expression, t, errors);
- }
-
- bool _inferInstanceCreationExpression(
- InstanceCreationExpression e, DartType t, errors) {
- var arguments = e.argumentList.arguments;
- var rawType = rules.getStaticType(e);
- // rawType is the instantiated type of the instance
- if (rawType is! InterfaceType) return false;
- var type = (rawType as InterfaceType);
- if (type.typeParameters == null ||
- type.typeParameters.length == 0) return false;
- if (e.constructorName.type == null) return false;
- // classTypeName is the type name of the class being instantiated
- var classTypeName = e.constructorName.type;
- // Check that we were not passed any type arguments
- if (classTypeName.typeArguments != null) return false;
- // Infer type arguments
- if (t is! InterfaceType) return false;
- var targs = _matchTypes(type, t);
- if (targs == null) return false;
- if (e.staticElement == null) return false;
- var constructorElement = e.staticElement;
- // From the constructor element get:
- // the instantiated type of the constructor, then
- // the uninstantiated element for the constructor, then
- // the uninstantiated type for the constructor
- var rawConstructorElement =
- constructorElement.type.element as ConstructorElement;
- var baseType = rawConstructorElement.type;
- if (baseType == null) return false;
- // From the interface type (instantiated), get:
- // the uninstantiated element, then
- // the uninstantiated type, then
- // the type arguments (aka the type parameters)
- var tparams = type.element.type.typeArguments;
- // Take the uninstantiated constructor type, and replace the type
- // parameters with the inferred arguments.
- var fType = baseType.substitute2(targs, tparams);
- {
- var rTypes = fType.normalParameterTypes;
- var oTypes = fType.optionalParameterTypes;
- var pTypes = new List.from(rTypes)..addAll(oTypes);
- var pArgs = arguments.where((x) => x is! NamedExpression);
- var pi = 0;
- for (var arg in pArgs) {
- if (pi >= pTypes.length) return false;
- var argType = pTypes[pi];
- if (!_inferExpression(arg, argType, errors)) return false;
- pi++;
- }
- var nTypes = fType.namedParameterTypes;
- for (var arg0 in arguments) {
- if (arg0 is! NamedExpression) continue;
- var arg = arg0 as NamedExpression;
- SimpleIdentifier nameNode = arg.name.label;
- String name = nameNode.name;
- var argType = nTypes[name];
- if (argType == null) return false;
- if (!_inferExpression(arg, argType, errors)) return false;
- }
- }
- annotateInstanceCreationExpression(e, targs);
- return true;
- }
-
- bool _inferNamedExpression(NamedExpression e, DartType t, errors) {
- return _inferExpression(e.expression, t, errors);
- }
-
- bool _inferFunctionExpression(FunctionExpression e, DartType t, errors) {
- if (t is! FunctionType) return false;
- var fType = t as FunctionType;
- var eType = e.staticType as FunctionType;
- if (eType is! FunctionType) return false;
-
- // We have a function literal, so we can treat the arrow type
- // as non-fuzzy. Since we're not improving on parameter types
- // currently, if this check fails then we cannot succeed, so
- // bail out. Otherwise, we never need to check the parameter types
- // again.
- if (!rules.isFunctionSubTypeOf(eType, fType,
- fuzzyArrows: false, ignoreReturn: true)) return false;
-
- // This only entered inference because of fuzzy typing.
- // The function type is already specific enough, we can just
- // succeed and treat it as a successful inference
- if (rules.isSubTypeOf(eType.returnType, fType.returnType)) return true;
-
- // Fuzzy typing again, handle the void case (not caught by the previous)
- if (fType.returnType.isVoid) return true;
-
- if (e.body is! ExpressionFunctionBody) return false;
- var body = (e.body as ExpressionFunctionBody).expression;
- if (!_inferExpression(body, fType.returnType, errors)) return false;
-
- // TODO(leafp): Try narrowing the argument types if possible
- // to get better code in the function body. This requires checking
- // that the body is well-typed at the more specific type.
-
- // At this point, we know that the parameter types are in the appropriate subtype
- // relation, and we have checked that we can type the body at the appropriate return
- // type, so we can are done.
- annotateFunctionExpression(e, fType.returnType);
- return true;
- }
-
- bool _inferListLiteral(ListLiteral e, DartType t, errors) {
- var dyn = rules.provider.dynamicType;
- var listT = rules.provider.listType.substitute4([dyn]);
- // List <: t (using dart rules) must be true
- if (!listT.isSubtypeOf(t)) return false;
- // The list literal must have no type arguments
- if (e.typeArguments != null) return false;
- if (t is! InterfaceType) return false;
- var targs = _matchTypes(listT, t);
- if (targs == null) return false;
- assert(targs.length == 1);
- var etype = targs[0];
- assert(!etype.isDynamic);
- var elements = e.elements;
- var b = elements.every((e) => _inferExpression(e, etype, errors));
- if (b) annotateListLiteral(e, targs);
- return b;
- }
-
- bool _inferMapLiteral(MapLiteral e, DartType t, errors) {
- var dyn = rules.provider.dynamicType;
- var mapT = rules.provider.mapType.substitute4([dyn, dyn]);
- // Map <: t (using dart rules) must be true
- if (!mapT.isSubtypeOf(t)) return false;
- // The map literal must have no type arguments
- if (e.typeArguments != null) return false;
- if (t is! InterfaceType) return false;
- var targs = _matchTypes(mapT, t);
- if (targs == null) return false;
- assert(targs.length == 2);
- var kType = targs[0];
- var vType = targs[1];
- assert(!(kType.isDynamic && vType.isDynamic));
- var entries = e.entries;
- bool inferEntry(MapLiteralEntry entry) {
- return _inferExpression(entry.key, kType, errors) &&
- _inferExpression(entry.value, vType, errors);
- }
- var b = entries.every(inferEntry);
- if (b) annotateMapLiteral(e, targs);
- return b;
- }
}
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index af67453..c7d0c57 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -350,7 +350,7 @@
*
* Clients may not extend, implement or mix-in this class.
*/
-abstract class ListTaskInput<E> extends TaskInput<List<E>> {
+abstract class ListTaskInput<E> implements TaskInput<List<E>> {
/**
* Return a task input that can be used to compute a flatten list whose
* elements are combined [subListResult]'s associated with those elements.
@@ -392,7 +392,7 @@
*
* Clients may not extend, implement or mix-in this class.
*/
-abstract class MapTaskInput<K, V> extends TaskInput<Map<K, V>> {
+abstract class MapTaskInput<K, V> implements TaskInput<Map<K, V>> {
/**
* [V] must be a [List].
* Return a task input that can be used to compute a list whose elements are
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 1973fb9..a3c4b51 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.26.2+1
+version: 0.26.3
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/ast_test.dart b/pkg/analyzer/test/generated/ast_test.dart
index e25c253..947ca7f 100644
--- a/pkg/analyzer/test/generated/ast_test.dart
+++ b/pkg/analyzer/test/generated/ast_test.dart
@@ -29,6 +29,7 @@
runReflectiveTests(IndexExpressionTest);
runReflectiveTests(NodeListTest);
runReflectiveTests(NodeLocatorTest);
+ runReflectiveTests(NodeLocator2Test);
runReflectiveTests(SimpleIdentifierTest);
runReflectiveTests(SimpleStringLiteralTest);
runReflectiveTests(StringInterpolationTest);
@@ -945,6 +946,50 @@
}
@reflectiveTest
+class NodeLocator2Test extends ParserTestCase {
+ void test_onlyStartOffset() {
+ String code = ' int vv; ';
+ // 012345678
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+ TopLevelVariableDeclaration declaration = unit.declarations[0];
+ VariableDeclarationList variableList = declaration.variables;
+ Identifier typeName = variableList.type.name;
+ SimpleIdentifier varName = variableList.variables[0].name;
+ expect(new NodeLocator2(0).searchWithin(unit), same(unit));
+ expect(new NodeLocator2(1).searchWithin(unit), same(typeName));
+ expect(new NodeLocator2(2).searchWithin(unit), same(typeName));
+ expect(new NodeLocator2(3).searchWithin(unit), same(typeName));
+ expect(new NodeLocator2(4).searchWithin(unit), same(variableList));
+ expect(new NodeLocator2(5).searchWithin(unit), same(varName));
+ expect(new NodeLocator2(6).searchWithin(unit), same(varName));
+ expect(new NodeLocator2(7).searchWithin(unit), same(declaration));
+ expect(new NodeLocator2(8).searchWithin(unit), same(unit));
+ expect(new NodeLocator2(9).searchWithin(unit), isNull);
+ expect(new NodeLocator2(100).searchWithin(unit), isNull);
+ }
+
+ void test_startEndOffset() {
+ String code = ' int vv; ';
+ // 012345678
+ CompilationUnit unit = ParserTestCase.parseCompilationUnit(code);
+ TopLevelVariableDeclaration declaration = unit.declarations[0];
+ VariableDeclarationList variableList = declaration.variables;
+ Identifier typeName = variableList.type.name;
+ SimpleIdentifier varName = variableList.variables[0].name;
+ expect(new NodeLocator2(-1, 2).searchWithin(unit), isNull);
+ expect(new NodeLocator2(0, 2).searchWithin(unit), same(unit));
+ expect(new NodeLocator2(1, 2).searchWithin(unit), same(typeName));
+ expect(new NodeLocator2(1, 3).searchWithin(unit), same(typeName));
+ expect(new NodeLocator2(1, 4).searchWithin(unit), same(variableList));
+ expect(new NodeLocator2(5, 6).searchWithin(unit), same(varName));
+ expect(new NodeLocator2(5, 7).searchWithin(unit), same(declaration));
+ expect(new NodeLocator2(5, 8).searchWithin(unit), same(unit));
+ expect(new NodeLocator2(5, 100).searchWithin(unit), isNull);
+ expect(new NodeLocator2(100, 200).searchWithin(unit), isNull);
+ }
+}
+
+@reflectiveTest
class NodeLocatorTest extends ParserTestCase {
void test_range() {
CompilationUnit unit =
@@ -2290,6 +2335,13 @@
_assertSource("continue;", AstFactory.continueStatement());
}
+ void test_visitDefaultFormalParameter_annotation() {
+ DefaultFormalParameter parameter = AstFactory.positionalFormalParameter(
+ AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0));
+ parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+ _assertSource('@A p = 0', parameter);
+ }
+
void test_visitDefaultFormalParameter_named_noValue() {
_assertSource(
"p",
@@ -2318,13 +2370,6 @@
AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0)));
}
- void test_visitDefaultFormalParameter_annotation() {
- DefaultFormalParameter parameter = AstFactory.positionalFormalParameter(
- AstFactory.simpleFormalParameter3("p"), AstFactory.integer(0));
- parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
- _assertSource('@A p = 0', parameter);
- }
-
void test_visitDoStatement() {
_assertSource(
"do {} while (c);",
@@ -2423,6 +2468,12 @@
_assertSource("@deprecated var a;", declaration);
}
+ void test_visitFieldFormalParameter_annotation() {
+ FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('f');
+ parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+ _assertSource('@A this.f', parameter);
+ }
+
void test_visitFieldFormalParameter_functionTyped() {
_assertSource(
"A this.a(b)",
@@ -2467,12 +2518,6 @@
AstFactory.fieldFormalParameter(null, AstFactory.typeName4("A"), "a"));
}
- void test_visitFieldFormalParameter_annotation() {
- FieldFormalParameter parameter = AstFactory.fieldFormalParameter2('f');
- parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
- _assertSource('@A this.f', parameter);
- }
-
void test_visitForEachStatement_declared() {
_assertSource(
"for (var a in b) {}",
@@ -2907,16 +2952,17 @@
_assertSource("@deprecated typedef A F();", declaration);
}
- void test_visitFunctionTypedFormalParameter_noType() {
- _assertSource("f()", AstFactory.functionTypedFormalParameter(null, "f"));
- }
-
void test_visitFunctionTypedFormalParameter_annotation() {
- FunctionTypedFormalParameter parameter = AstFactory.functionTypedFormalParameter(null, "f");
+ FunctionTypedFormalParameter parameter =
+ AstFactory.functionTypedFormalParameter(null, "f");
parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
_assertSource('@A f()', parameter);
}
+ void test_visitFunctionTypedFormalParameter_noType() {
+ _assertSource("f()", AstFactory.functionTypedFormalParameter(null, "f"));
+ }
+
void test_visitFunctionTypedFormalParameter_type() {
_assertSource(
"T f()",
@@ -3524,6 +3570,12 @@
_assertSource(scriptTag, AstFactory.scriptTag(scriptTag));
}
+ void test_visitSimpleFormalParameter_annotation() {
+ SimpleFormalParameter parameter = AstFactory.simpleFormalParameter3('x');
+ parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
+ _assertSource('@A x', parameter);
+ }
+
void test_visitSimpleFormalParameter_keyword() {
_assertSource("var a", AstFactory.simpleFormalParameter(Keyword.VAR, "a"));
}
@@ -3540,12 +3592,6 @@
AstFactory.simpleFormalParameter4(AstFactory.typeName4("A"), "a"));
}
- void test_visitSimpleFormalParameter_annotation() {
- SimpleFormalParameter parameter = AstFactory.simpleFormalParameter3('x');
- parameter.metadata.add(AstFactory.annotation(AstFactory.identifier3("A")));
- _assertSource('@A x', parameter);
- }
-
void test_visitSimpleIdentifier() {
_assertSource("a", AstFactory.identifier3("a"));
}
diff --git a/pkg/analyzer/test/generated/compile_time_error_code_test.dart b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
index 851a4ee..154d448 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -1635,9 +1635,28 @@
class A {}''');
computeLibrarySourceErrors(librarySource);
assertErrors(sourceB, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
+ assertNoErrors(librarySource);
verify([librarySource, sourceA, sourceB]);
}
+ void test_duplicateDefinition_inPart() {
+ Source librarySource = addNamedSource(
+ "/lib.dart",
+ r'''
+library test;
+part 'a.dart';
+class A {}''');
+ Source sourceA = addNamedSource(
+ "/a.dart",
+ r'''
+part of test;
+class A {}''');
+ computeLibrarySourceErrors(librarySource);
+ assertErrors(sourceA, [CompileTimeErrorCode.DUPLICATE_DEFINITION]);
+ assertNoErrors(librarySource);
+ verify([librarySource, sourceA]);
+ }
+
void test_duplicateDefinition_catch() {
Source source = addSource(r'''
main() {
diff --git a/pkg/analyzer/test/generated/declaration_resolver_test.dart b/pkg/analyzer/test/generated/declaration_resolver_test.dart
new file mode 100644
index 0000000..a3d0b66
--- /dev/null
+++ b/pkg/analyzer/test/generated/declaration_resolver_test.dart
@@ -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;
+ }
+}
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index eaef165..dd9394c 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -5,9 +5,10 @@
library engine.incremental_resolver_test;
import 'package:analyzer/src/context/cache.dart' as task;
+import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/engine.dart' hide AnalysisCache;
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/incremental_logger.dart' as log;
import 'package:analyzer/src/generated/incremental_resolution_validator.dart';
@@ -19,6 +20,7 @@
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/generated/testing/ast_factory.dart';
import 'package:analyzer/src/generated/testing/element_factory.dart';
+import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/task/dart.dart';
import 'package:unittest/unittest.dart';
@@ -3519,17 +3521,10 @@
@override
void setUp() {
- AnalysisEngine.instance.useTaskModel = true;
super.setUp();
_resetWithIncremental(true);
}
- @override
- void tearDown() {
- super.tearDown();
- AnalysisEngine.instance.useTaskModel = false;
- }
-
void test_computeConstants() {
_resolveUnit(r'''
int f() => 0;
@@ -4460,6 +4455,41 @@
''');
}
+ void test_updateErrors_invalidVerifyErrors() {
+ _resolveUnit(r'''
+main() {
+ foo('aaa');
+}
+main2() {
+ foo('bbb');
+}
+foo(int p) {}
+''');
+ // Complete analysis, e.g. compute VERIFY_ERRORS.
+ _runTasks();
+ // Invalidate VERIFY_ERRORS.
+ AnalysisCache cache = analysisContext2.analysisCache;
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ task.CacheEntry cacheEntry = cache.get(target);
+ expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(2));
+ cacheEntry.setState(VERIFY_ERRORS, CacheState.INVALID);
+ // Don't run tasks, so don't recompute VERIFY_ERRORS before incremental.
+ _updateAndValidate(
+ r'''
+main() {
+ foo(0);
+}
+main2() {
+ foo('bbb');
+}
+foo(int p) {}
+''',
+ runTasksBeforeIncremental: false);
+ // Incremental analysis should have left VERIFY_ERRORS invalid,
+ // so it was correctly recomputed later during the full analysis.
+ expect(cacheEntry.getValue(VERIFY_ERRORS), hasLength(1));
+ }
+
void test_updateErrors_removeExisting_hint() {
_resolveUnit(r'''
int main() {
@@ -4595,9 +4625,13 @@
}
void _updateAndValidate(String newCode,
- {bool expectedSuccess: true, bool compareWithFull: true}) {
+ {bool expectedSuccess: true,
+ bool compareWithFull: true,
+ bool runTasksBeforeIncremental: true}) {
// Run any pending tasks tasks.
- _runTasks();
+ if (runTasksBeforeIncremental) {
+ _runTasks();
+ }
// Update the source - currently this may cause incremental resolution.
// Then request the updated resolved unit.
_resetWithIncremental(true);
@@ -4613,7 +4647,8 @@
// The existing CompilationUnit[Element] should be updated.
expect(newUnit, same(oldUnit));
expect(newUnit.element, same(oldUnitElement));
- expect(analysisContext.parseCompilationUnit(source), same(oldUnit));
+ expect(analysisContext.getResolvedCompilationUnit(source, oldLibrary),
+ same(oldUnit));
// The only expected pending task should return the same resolved
// "newUnit", so all clients will get it using the usual way.
AnalysisResult analysisResult = analysisContext.performAnalysisTask();
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 42e49e4..d3c995c 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -6954,6 +6954,12 @@
expect(declaration.propertyKeyword, isNull);
}
+ void test_parseCompilationUnitMember_function_void() {
+ FunctionDeclaration declaration = parse("parseCompilationUnitMember",
+ <Object>[emptyCommentAndMetadata()], "void f() {}");
+ expect(declaration.returnType, isNotNull);
+ }
+
void test_parseCompilationUnitMember_function_withTypeParameters() {
enableGenericMethods = true;
FunctionDeclaration declaration = parse("parseCompilationUnitMember",
@@ -6962,12 +6968,6 @@
expect(declaration.propertyKeyword, isNull);
}
- void test_parseCompilationUnitMember_function_void() {
- FunctionDeclaration declaration = parse("parseCompilationUnitMember",
- <Object>[emptyCommentAndMetadata()], "void f() {}");
- expect(declaration.returnType, isNotNull);
- }
-
void test_parseCompilationUnitMember_getter_external_noType() {
FunctionDeclaration declaration = parse("parseCompilationUnitMember",
<Object>[emptyCommentAndMetadata()], "external get p;");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 7c6bece..da69a28 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -68,6 +68,7 @@
runReflectiveTests(SimpleResolverTest);
runReflectiveTests(StrictModeTest);
runReflectiveTests(TypePropagationTest);
+ runReflectiveTests(StrongModeDownwardsInferenceTest);
runReflectiveTests(StrongModeStaticTypeAnalyzer2Test);
runReflectiveTests(StrongModeTypePropagationTest);
}
@@ -203,23 +204,27 @@
futureConstructor.factory = true;
futureElement.constructors = <ConstructorElement>[futureConstructor];
// Future then(onValue(T value), { Function onError });
- List<ParameterElement> parameters = <ParameterElement>[
- ElementFactory.requiredParameter2(
- "value", futureElement.typeParameters[0].type)
- ];
- FunctionElementImpl onValueFunction = new FunctionElementImpl.forNode(null);
- onValueFunction.synthetic = true;
- onValueFunction.parameters = parameters;
- onValueFunction.returnType = provider.dynamicType;
- onValueFunction.enclosingElement = futureElement;
- onValueFunction.type = new FunctionTypeImpl(onValueFunction);
- DartType futureDynamicType =
- futureElement.type.substitute4([provider.dynamicType]);
- MethodElement thenMethod = ElementFactory.methodElementWithParameters(
- futureElement, "then", futureDynamicType, [
- ElementFactory.requiredParameter2("onValue", onValueFunction.type),
+ TypeDefiningElement futureThenR = DynamicElementImpl.instance;
+ if (context.analysisOptions.strongMode) {
+ futureThenR = ElementFactory.typeParameterWithType('R');
+ }
+ FunctionElementImpl thenOnValue = ElementFactory.functionElement3(
+ 'onValue', futureThenR, [futureElement.typeParameters[0]], null);
+
+ DartType futureRType = futureElement.type.substitute4([futureThenR.type]);
+ MethodElementImpl thenMethod = ElementFactory.methodElementWithParameters(
+ futureElement, "then", futureRType, [
+ ElementFactory.requiredParameter2("onValue", thenOnValue.type),
ElementFactory.namedParameter2("onError", provider.functionType)
]);
+ if (!futureThenR.type.isDynamic) {
+ thenMethod.typeParameters = [futureThenR];
+ }
+ thenOnValue.enclosingElement = thenMethod;
+ thenOnValue.type = new FunctionTypeImpl(thenOnValue);
+ (thenMethod.parameters[0] as ParameterElementImpl).type = thenOnValue.type;
+ thenMethod.type = new FunctionTypeImpl(thenMethod);
+
futureElement.methods = <MethodElement>[thenMethod];
// Completer
ClassElementImpl completerElement =
@@ -340,11 +345,12 @@
ClassElement.EMPTY_LIST);
TopLevelVariableElement ln10Element = ElementFactory
.topLevelVariableElement3("LN10", true, false, provider.doubleType);
- FunctionElement maxElement = ElementFactory.functionElement3(
- "max",
- provider.numType.element,
- <ClassElement>[provider.numType.element, provider.numType.element],
- ClassElement.EMPTY_LIST);
+ TypeParameterElement maxT =
+ ElementFactory.typeParameterWithType('T', provider.numType);
+ FunctionElementImpl maxElement = ElementFactory.functionElement3(
+ "max", maxT, [maxT, maxT], ClassElement.EMPTY_LIST);
+ maxElement.typeParameters = [maxT];
+ maxElement.type = new FunctionTypeImpl(maxElement);
TopLevelVariableElement piElement = ElementFactory.topLevelVariableElement3(
"PI", true, false, provider.doubleType);
ClassElementImpl randomElement = ElementFactory.classElement2("Random");
@@ -12127,6 +12133,983 @@
}
/**
+ * Strong mode static analyzer downwards inference tests
+ */
+@reflectiveTest
+class StrongModeDownwardsInferenceTest extends ResolverTestCase {
+ TypeAssertions _assertions;
+ AsserterBuilder<Element, DartType> _hasElement;
+ AsserterBuilder<DartType, DartType> _isType;
+ AsserterBuilder2<Asserter<DartType>, Asserter<DartType>,
+ DartType> _isFunction2Of;
+ AsserterBuilderBuilder<Asserter<DartType>, List<Asserter<DartType>>,
+ DartType> _isInstantiationOf;
+ Asserter<DartType> _isInt;
+ Asserter<DartType> _isNum;
+ Asserter<DartType> _isString;
+ Asserter<DartType> _isDynamic;
+ AsserterBuilder<Asserter<DartType>, InterfaceType> _isListOf;
+ AsserterBuilder2<Asserter<DartType>, Asserter<DartType>,
+ InterfaceType> _isMapOf;
+
+ @override
+ void setUp() {
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ options.strongMode = true;
+ resetWithOptions(options);
+ _assertions = new TypeAssertions(typeProvider);
+ _isType = _assertions.isType;
+ _hasElement = _assertions.hasElement;
+ _isInstantiationOf = _assertions.isInstantiationOf;
+ _isInt = _assertions.isInt;
+ _isNum = _assertions.isNum;
+ _isString = _assertions.isString;
+ _isDynamic = _assertions.isDynamic;
+ _isListOf = _assertions.isListOf;
+ _isMapOf = _assertions.isMapOf;
+ _isFunction2Of = _assertions.isFunction2Of;
+ }
+
+ void test_cascadeExpression() {
+ String code = r'''
+ class A<T> {
+ List<T> map(T a, List<T> mapper(T x)) => mapper(a);
+ }
+
+ void main () {
+ A<int> a = new A()..map(0, (x) => [x]);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ CascadeExpression fetch(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ CascadeExpression exp = decl.initializer;
+ return exp;
+ }
+ Element elementA = AstFinder.getClass(unit, "A").element;
+
+ CascadeExpression cascade = fetch(0);
+ _isInstantiationOf(_hasElement(elementA))([_isInt])(cascade.staticType);
+ MethodInvocation invoke = cascade.cascadeSections[0];
+ FunctionExpression function = invoke.argumentList.arguments[1];
+ ExecutableElement f0 = function.element;
+ _isListOf(_isInt)(f0.type.returnType);
+ expect(f0.type.normalParameterTypes[0], typeProvider.intType);
+ }
+
+ void test_constructorInitializer_propagation() {
+ String code = r'''
+ class A {
+ List<String> x;
+ A() : this.x = [];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ ConstructorFieldInitializer assignment = constructor.initializers[0];
+ Expression exp = assignment.expression;
+ _isListOf(_isString)(exp.staticType);
+ }
+
+ void test_factoryConstructor_propagation() {
+ String code = r'''
+ class A<T> {
+ factory A() { return new B(); }
+ }
+ class B<S> extends A<S> {}
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ BlockFunctionBody body = constructor.body;
+ ReturnStatement stmt = body.block.statements[0];
+ InstanceCreationExpression exp = stmt.expression;
+ ClassElement elementB = AstFinder.getClass(unit, "B").element;
+ ClassElement elementA = AstFinder.getClass(unit, "A").element;
+ expect(exp.constructorName.type.type.element, elementB);
+ _isInstantiationOf(_hasElement(elementB))(
+ [_isType(elementA.typeParameters[0].type)])(exp.staticType);
+ }
+
+ void test_fieldDeclaration_propagation() {
+ String code = r'''
+ class A {
+ List<String> f0 = ["hello"];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ VariableDeclaration field = AstFinder.getFieldInClass(unit, "A", "f0");
+
+ _isListOf(_isString)(field.initializer.staticType);
+ }
+
+ void test_functionDeclaration_body_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ List<int> test1() => [];
+
+ Function2<int, int> test2 (int x) {
+ Function2<String, int> inner() {
+ return (x) => x.length;
+ }
+ return (x) => x;
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ FunctionDeclaration test1 = AstFinder.getTopLevelFunction(unit, "test1");
+ ExpressionFunctionBody body = test1.functionExpression.body;
+ assertListOfInt(body.expression.staticType);
+
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+
+ FunctionDeclaration inner =
+ (statements[0] as FunctionDeclarationStatement).functionDeclaration;
+ BlockFunctionBody body0 = inner.functionExpression.body;
+ ReturnStatement return0 = body0.block.statements[0];
+ Expression anon0 = return0.expression;
+ FunctionType type0 = anon0.staticType;
+ expect(type0.returnType, typeProvider.intType);
+ expect(type0.normalParameterTypes[0], typeProvider.stringType);
+
+ FunctionExpression anon1 = (statements[1] as ReturnStatement).expression;
+ FunctionType type1 = anon1.element.type;
+ expect(type1.returnType, typeProvider.intType);
+ expect(type1.normalParameterTypes[0], typeProvider.intType);
+ }
+
+ void test_functionLiteral_assignment_typedArguments() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, String> l0 = (int x) => null;
+ Function2<int, String> l1 = (int x) => "hello";
+ Function2<int, String> l2 = (String x) => "hello";
+ Function2<int, String> l3 = (int x) => 3;
+ Function2<int, String> l4 = (int x) {return 3;};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_assignment_unTypedArguments() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, String> l0 = (x) => null;
+ Function2<int, String> l1 = (x) => "hello";
+ Function2<int, String> l2 = (x) => "hello";
+ Function2<int, String> l3 = (x) => 3;
+ Function2<int, String> l4 = (x) {return 3;};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_body_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, List<String>> l0 = (int x) => ["hello"];
+ Function2<int, List<String>> l1 = (String x) => ["hello"];
+ Function2<int, List<String>> l2 = (int x) => [3];
+ Function2<int, List<String>> l3 = (int x) {return [3];};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ Expression functionReturnValue(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ FunctionBody body = exp.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ assertListOfString(functionReturnValue(0).staticType);
+ assertListOfString(functionReturnValue(1).staticType);
+ assertListOfString(functionReturnValue(2).staticType);
+ assertListOfString(functionReturnValue(3).staticType);
+ }
+
+ void test_functionLiteral_functionExpressionInvocation_typedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ (new Mapper<int, String>().map)((int x) => null);
+ (new Mapper<int, String>().map)((int x) => "hello");
+ (new Mapper<int, String>().map)((String x) => "hello");
+ (new Mapper<int, String>().map)((int x) => 3);
+ (new Mapper<int, String>().map)((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ FunctionExpressionInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionExpressionInvocation_unTypedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ (new Mapper<int, String>().map)((x) => null);
+ (new Mapper<int, String>().map)((x) => "hello");
+ (new Mapper<int, String>().map)((x) => "hello");
+ (new Mapper<int, String>().map)((x) => 3);
+ (new Mapper<int, String>().map)((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ FunctionExpressionInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionInvocation_typedArguments() {
+ String code = r'''
+ String map(String mapper(int x)) => mapper(null);
+
+ void main () {
+ map((int x) => null);
+ map((int x) => "hello");
+ map((String x) => "hello");
+ map((int x) => 3);
+ map((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_functionInvocation_unTypedArguments() {
+ String code = r'''
+ String map(String mapper(int x)) => mapper(null);
+
+ void main () {
+ map((x) => null);
+ map((x) => "hello");
+ map((x) => "hello");
+ map((x) => 3);
+ map((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_methodInvocation_typedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ new Mapper<int, String>().map((int x) => null);
+ new Mapper<int, String>().map((int x) => "hello");
+ new Mapper<int, String>().map((String x) => "hello");
+ new Mapper<int, String>().map((int x) => 3);
+ new Mapper<int, String>().map((int x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isString, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_methodInvocation_unTypedArguments() {
+ String code = r'''
+ class Mapper<F, T> {
+ T map(T mapper(F x)) => mapper(null);
+ }
+
+ void main () {
+ new Mapper<int, String>().map((x) => null);
+ new Mapper<int, String>().map((x) => "hello");
+ new Mapper<int, String>().map((x) => "hello");
+ new Mapper<int, String>().map((x) => 3);
+ new Mapper<int, String>().map((x) {return 3;});
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ ExpressionStatement stmt = statements[i];
+ MethodInvocation invk = stmt.expression;
+ FunctionExpression exp = invk.argumentList.arguments[0];
+ return exp.element.type;
+ }
+ _isFunction2Of(_isInt, _isString)(literal(0));
+ _isFunction2Of(_isInt, _isString)(literal(1));
+ _isFunction2Of(_isInt, _isString)(literal(2));
+ _isFunction2Of(_isInt, _isInt)(literal(3));
+ _isFunction2Of(_isInt, _isString)(literal(4));
+ }
+
+ void test_functionLiteral_unTypedArgument_propagation() {
+ String code = r'''
+ typedef T Function2<S, T>(S x);
+
+ void main () {
+ Function2<int, int> l0 = (x) => x;
+ Function2<int, int> l1 = (x) => x+1;
+ Function2<int, String> l2 = (x) => x;
+ Function2<int, String> l3 = (x) => x.toLowerCase();
+ Function2<String, String> l4 = (x) => x.toLowerCase();
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ Expression functionReturnValue(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ FunctionExpression exp = decl.initializer;
+ FunctionBody body = exp.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ expect(functionReturnValue(0).staticType, typeProvider.intType);
+ expect(functionReturnValue(1).staticType, typeProvider.intType);
+ expect(functionReturnValue(2).staticType, typeProvider.intType);
+ expect(functionReturnValue(3).staticType, typeProvider.dynamicType);
+ 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> {
+ S x;
+ T y;
+ A(this.x, this.y);
+ A.named(this.x, this.y);
+ }
+
+ class B<S, T> extends A<T, S> {
+ B(S y, T x) : super(x, y);
+ B.named(S y, T x) : super.named(x, y);
+ }
+
+ class C<S> extends B<S, S> {
+ C(S a) : super(a, a);
+ C.named(S a) : super.named(a, a);
+ }
+
+ class D<S, T> extends B<T, int> {
+ D(T a) : super(a, 3);
+ D.named(T a) : super.named(a, 3);
+ }
+
+ class E<S, T> extends A<C<S>, T> {
+ E(T a) : super(null, a);
+ }
+
+ class F<S, T> extends A<S, T> {
+ F(S x, T y, {List<S> a, List<T> b}) : super(x, y);
+ F.named(S x, T y, [S a, T b]) : super(a, b);
+ }
+
+ void test0() {
+ A<int, String> a0 = new A(3, "hello");
+ A<int, String> a1 = new A.named(3, "hello");
+ A<int, String> a2 = new A<int, String>(3, "hello");
+ A<int, String> a3 = new A<int, String>.named(3, "hello");
+ A<int, String> a4 = new A<int, dynamic>(3, "hello");
+ A<int, String> a5 = new A<dynamic, dynamic>.named(3, "hello");
+ }
+ void test1() {
+ A<int, String> a0 = new A("hello", 3);
+ A<int, String> a1 = new A.named("hello", 3);
+ }
+ void test2() {
+ A<int, String> a0 = new B("hello", 3);
+ A<int, String> a1 = new B.named("hello", 3);
+ A<int, String> a2 = new B<String, int>("hello", 3);
+ A<int, String> a3 = new B<String, int>.named("hello", 3);
+ A<int, String> a4 = new B<String, dynamic>("hello", 3);
+ A<int, String> a5 = new B<dynamic, dynamic>.named("hello", 3);
+ }
+ void test3() {
+ A<int, String> a0 = new B(3, "hello");
+ A<int, String> a1 = new B.named(3, "hello");
+ }
+ void test4() {
+ A<int, int> a0 = new C(3);
+ A<int, int> a1 = new C.named(3);
+ A<int, int> a2 = new C<int>(3);
+ A<int, int> a3 = new C<int>.named(3);
+ A<int, int> a4 = new C<dynamic>(3);
+ A<int, int> a5 = new C<dynamic>.named(3);
+ }
+ void test5() {
+ A<int, int> a0 = new C("hello");
+ A<int, int> a1 = new C.named("hello");
+ }
+ void test6() {
+ A<int, String> a0 = new D("hello");
+ A<int, String> a1 = new D.named("hello");
+ A<int, String> a2 = new D<int, String>("hello");
+ A<int, String> a3 = new D<String, String>.named("hello");
+ A<int, String> a4 = new D<num, dynamic>("hello");
+ A<int, String> a5 = new D<dynamic, dynamic>.named("hello");
+ }
+ void test7() {
+ A<int, String> a0 = new D(3);
+ A<int, String> a1 = new D.named(3);
+ }
+ void test8() {
+ // Currently we only allow variable constraints. Test that we reject.
+ A<C<int>, String> a0 = new E("hello");
+ }
+ void test9() { // Check named and optional arguments
+ A<int, String> a0 = new F(3, "hello", a: [3], b: ["hello"]);
+ A<int, String> a1 = new F(3, "hello", a: ["hello"], b:[3]);
+ A<int, String> a2 = new F.named(3, "hello", 3, "hello");
+ A<int, String> a3 = new F.named(3, "hello");
+ A<int, String> a4 = new F.named(3, "hello", "hello", 3);
+ A<int, String> a5 = new F.named(3, "hello", "hello");
+ }
+ }''';
+ CompilationUnit unit = resolveSource(code);
+
+ Expression rhs(VariableDeclarationStatement stmt) {
+ VariableDeclaration decl = stmt.variables.variables[0];
+ Expression exp = decl.initializer;
+ return exp;
+ }
+
+ void hasType(Asserter<DartType> assertion, Expression exp) =>
+ assertion(exp.staticType);
+
+ Element elementA = AstFinder.getClass(unit, "A").element;
+ Element elementB = AstFinder.getClass(unit, "B").element;
+ Element elementC = AstFinder.getClass(unit, "C").element;
+ Element elementD = AstFinder.getClass(unit, "D").element;
+ Element elementE = AstFinder.getClass(unit, "E").element;
+ Element elementF = AstFinder.getClass(unit, "F").element;
+
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertAOf =
+ _isInstantiationOf(_hasElement(elementA));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertBOf =
+ _isInstantiationOf(_hasElement(elementB));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertCOf =
+ _isInstantiationOf(_hasElement(elementC));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertDOf =
+ _isInstantiationOf(_hasElement(elementD));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertEOf =
+ _isInstantiationOf(_hasElement(elementE));
+ AsserterBuilder<List<Asserter<DartType>>, DartType> assertFOf =
+ _isInstantiationOf(_hasElement(elementF));
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test0");
+
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[3]));
+ hasType(assertAOf([_isInt, _isDynamic]), rhs(statements[4]));
+ hasType(assertAOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test1");
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertAOf([_isInt, _isString]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test2");
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[2]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[3]));
+ hasType(assertBOf([_isString, _isDynamic]), rhs(statements[4]));
+ hasType(assertBOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test3");
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[0]));
+ hasType(assertBOf([_isString, _isInt]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test4");
+ hasType(assertCOf([_isInt]), rhs(statements[0]));
+ hasType(assertCOf([_isInt]), rhs(statements[1]));
+ hasType(assertCOf([_isInt]), rhs(statements[2]));
+ hasType(assertCOf([_isInt]), rhs(statements[3]));
+ hasType(assertCOf([_isDynamic]), rhs(statements[4]));
+ hasType(assertCOf([_isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test5");
+ hasType(assertCOf([_isInt]), rhs(statements[0]));
+ hasType(assertCOf([_isInt]), rhs(statements[1]));
+ }
+
+ {
+ // The first type parameter is not constrained by the
+ // context. We could choose a tighter type, but currently
+ // we just use dynamic.
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test6");
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+ hasType(assertDOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertDOf([_isString, _isString]), rhs(statements[3]));
+ hasType(assertDOf([_isNum, _isDynamic]), rhs(statements[4]));
+ hasType(assertDOf([_isDynamic, _isDynamic]), rhs(statements[5]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test7");
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[0]));
+ hasType(assertDOf([_isDynamic, _isString]), rhs(statements[1]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test8");
+ hasType(assertEOf([_isDynamic, _isDynamic]), rhs(statements[0]));
+ }
+
+ {
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test9");
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[0]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[1]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[2]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[3]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[4]));
+ hasType(assertFOf([_isInt, _isString]), rhs(statements[5]));
+ }
+ }
+
+ void test_listLiteral_nested() {
+ String code = r'''
+ void main () {
+ List<List<int>> l0 = [[]];
+ Iterable<List<int>> l1 = [[3]];
+ Iterable<List<int>> l2 = [[3], [4]];
+ List<List<int>> l3 = [["hello", 3], []];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ ListLiteral literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+ Asserter<InterfaceType> assertListOfListOfInt = _isListOf(assertListOfInt);
+
+ assertListOfListOfInt(literal(0).staticType);
+ assertListOfListOfInt(literal(1).staticType);
+ assertListOfListOfInt(literal(2).staticType);
+ assertListOfListOfInt(literal(3).staticType);
+
+ assertListOfInt(literal(1).elements[0].staticType);
+ assertListOfInt(literal(2).elements[0].staticType);
+ assertListOfInt(literal(3).elements[0].staticType);
+ }
+
+ void test_listLiteral_simple() {
+ String code = r'''
+ void main () {
+ List<int> l0 = [];
+ List<int> l1 = [3];
+ List<int> l2 = ["hello"];
+ List<int> l3 = ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_listLiteral_simple_const() {
+ String code = r'''
+ void main () {
+ const List<int> c0 = const [];
+ const List<int> c1 = const [3];
+ const List<int> c2 = const ["hello"];
+ const List<int> c3 = const ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_listLiteral_simple_disabled() {
+ String code = r'''
+ void main () {
+ List<int> l0 = <num>[];
+ List<int> l1 = <num>[3];
+ List<int> l2 = <String>["hello"];
+ List<int> l3 = <dynamic>["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ _isListOf(_isNum)(literal(0));
+ _isListOf(_isNum)(literal(1));
+ _isListOf(_isString)(literal(2));
+ _isListOf(_isDynamic)(literal(3));
+ }
+
+ void test_listLiteral_simple_subtype() {
+ String code = r'''
+ void main () {
+ Iterable<int> l0 = [];
+ Iterable<int> l1 = [3];
+ Iterable<int> l2 = ["hello"];
+ Iterable<int> l3 = ["hello", 3];
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ ListLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertListOfInt = _isListOf(_isInt);
+
+ assertListOfInt(literal(0));
+ assertListOfInt(literal(1));
+ assertListOfInt(literal(2));
+ assertListOfInt(literal(3));
+ }
+
+ void test_mapLiteral_nested() {
+ String code = r'''
+ void main () {
+ Map<int, List<String>> l0 = {};
+ Map<int, List<String>> l1 = {3: ["hello"]};
+ Map<int, List<String>> l2 = {"hello": ["hello"]};
+ Map<int, List<String>> l3 = {3: [3]};
+ Map<int, List<String>> l4 = {3:["hello"], "hello": [3]};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ MapLiteral literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp;
+ }
+
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ Asserter<InterfaceType> assertMapOfIntToListOfString =
+ _isMapOf(_isInt, assertListOfString);
+
+ assertMapOfIntToListOfString(literal(0).staticType);
+ assertMapOfIntToListOfString(literal(1).staticType);
+ assertMapOfIntToListOfString(literal(2).staticType);
+ assertMapOfIntToListOfString(literal(3).staticType);
+ assertMapOfIntToListOfString(literal(4).staticType);
+
+ assertListOfString(literal(1).entries[0].value.staticType);
+ assertListOfString(literal(2).entries[0].value.staticType);
+ assertListOfString(literal(3).entries[0].value.staticType);
+ assertListOfString(literal(4).entries[0].value.staticType);
+ }
+
+ void test_mapLiteral_simple() {
+ String code = r'''
+ void main () {
+ Map<int, String> l0 = {};
+ Map<int, String> l1 = {3: "hello"};
+ Map<int, String> l2 = {"hello": "hello"};
+ Map<int, String> l3 = {3: 3};
+ Map<int, String> l4 = {3:"hello", "hello": 3};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertMapOfIntToString =
+ _isMapOf(_isInt, _isString);
+
+ assertMapOfIntToString(literal(0));
+ assertMapOfIntToString(literal(1));
+ assertMapOfIntToString(literal(2));
+ assertMapOfIntToString(literal(3));
+ }
+
+ void test_mapLiteral_simple_disabled() {
+ String code = r'''
+ void main () {
+ Map<int, String> l0 = <int, dynamic>{};
+ Map<int, String> l1 = <int, dynamic>{3: "hello"};
+ Map<int, String> l2 = <int, dynamic>{"hello": "hello"};
+ Map<int, String> l3 = <int, dynamic>{3: 3};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
+ DartType literal(int i) {
+ VariableDeclarationStatement stmt = statements[i];
+ VariableDeclaration decl = stmt.variables.variables[0];
+ MapLiteral exp = decl.initializer;
+ return exp.staticType;
+ }
+
+ Asserter<InterfaceType> assertMapOfIntToDynamic =
+ _isMapOf(_isInt, _isDynamic);
+
+ assertMapOfIntToDynamic(literal(0));
+ assertMapOfIntToDynamic(literal(1));
+ assertMapOfIntToDynamic(literal(2));
+ assertMapOfIntToDynamic(literal(3));
+ }
+
+ void test_methodDeclaration_body_propagation() {
+ String code = r'''
+ class A {
+ List<String> m0(int x) => ["hello"];
+ List<String> m1(int x) {return [3];};
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+ Expression methodReturnValue(String methodName) {
+ MethodDeclaration method =
+ AstFinder.getMethodInClass(unit, "A", methodName);
+ FunctionBody body = method.body;
+ if (body is ExpressionFunctionBody) {
+ return body.expression;
+ } else {
+ Statement stmt = (body as BlockFunctionBody).block.statements[0];
+ return (stmt as ReturnStatement).expression;
+ }
+ }
+ Asserter<InterfaceType> assertListOfString = _isListOf(_isString);
+ assertListOfString(methodReturnValue("m0").staticType);
+ assertListOfString(methodReturnValue("m1").staticType);
+ }
+
+ void test_redirectingConstructor_propagation() {
+ String code = r'''
+ class A {
+ A() : this.named([]);
+ A.named(List<String> x);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ RedirectingConstructorInvocation invocation = constructor.initializers[0];
+ Expression exp = invocation.argumentList.arguments[0];
+ _isListOf(_isString)(exp.staticType);
+ }
+
+ void test_superConstructorInvocation_propagation() {
+ String code = r'''
+ class B {
+ B(List<String>);
+ }
+ class A extends B {
+ A() : super([]);
+ }
+ ''';
+ CompilationUnit unit = resolveSource(code);
+
+ ConstructorDeclaration constructor =
+ AstFinder.getConstructorInClass(unit, "A", null);
+ SuperConstructorInvocation invocation = constructor.initializers[0];
+ Expression exp = invocation.argumentList.arguments[0];
+ _isListOf(_isString)(exp.staticType);
+ }
+}
+
+/**
* Strong mode static analyzer end to end tests
*/
@reflectiveTest
@@ -12173,21 +13156,15 @@
if (!AnalysisEngine.instance.useTaskModel) {
return;
}
- // TODO(jmesserly): we're missing a case in the parser for the return type,
- // so "dynamic" must be used to workaround this.
- _resolveTestUnit(r'''
-dynamic/*=T*/ f/*<T>*/(/*=T*/ x) => null;
-''');
+ _resolveTestUnit(r'/*=T*/ f/*<T>*/(/*=T*/ x) => null;');
SimpleIdentifier f = _findIdentifier('f');
FunctionElementImpl e = f.staticElement;
expect(e.typeParameters.toString(), '[T]');
- expect(e.type.typeParameters.toString(), '[T]');
- expect(e.type.typeParameters[0].type, e.type.typeArguments[0]);
- expect(e.type.toString(), '(T) → T');
+ expect(e.type.boundTypeParameters.toString(), '[T]');
+ expect(e.type.typeParameters.toString(), '[]');
+ expect(e.type.toString(), '<T>(T) → T');
- // Substitute for T
- DartType t = e.typeParameters[0].type;
- FunctionType ft = e.type.substitute2([typeProvider.stringType], [t]);
+ FunctionType ft = e.type.instantiate([typeProvider.stringType]);
expect(ft.toString(), '(String) → String');
}
@@ -12206,16 +13183,17 @@
SimpleIdentifier f = _findIdentifier('f');
MethodElementImpl e = f.staticElement;
expect(e.typeParameters.toString(), '[T]');
- expect(e.type.typeParameters.toString(), '[T, E]');
- expect(e.type.typeArguments.toString(), '[T, E]');
- expect(e.type.toString(), '(E) → List<T>');
+ expect(e.type.boundTypeParameters.toString(), '[T]');
+ expect(e.type.typeParameters.toString(), '[E]');
+ expect(e.type.typeArguments.toString(), '[E]');
+ expect(e.type.toString(), '<T>(E) → List<T>');
SimpleIdentifier c = _findIdentifier('cOfString');
FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
- expect(ft.toString(), '(String) → List<T>');
- DartType t = e.typeParameters[0].type;
- ft = ft.substitute2([typeProvider.intType], [t]);
+ expect(ft.toString(), '<T>(String) → List<T>');
+ ft = ft.instantiate([typeProvider.intType]);
expect(ft.toString(), '(String) → List<int>');
+ expect('${ft.typeArguments}/${ft.typeParameters}', '[String, int]/[E, T]');
}
void test_genericMethod_functionTypedParameter() {
@@ -12233,18 +13211,50 @@
SimpleIdentifier f = _findIdentifier('f');
MethodElementImpl e = f.staticElement;
expect(e.typeParameters.toString(), '[T]');
- expect(e.type.typeParameters.toString(), '[T, E]');
- expect(e.type.typeArguments.toString(), '[T, E]');
- expect(e.type.toString(), '((E) → T) → List<T>');
+ expect(e.type.boundTypeParameters.toString(), '[T]');
+ expect(e.type.typeParameters.toString(), '[E]');
+ expect(e.type.typeArguments.toString(), '[E]');
+ expect(e.type.toString(), '<T>((E) → T) → List<T>');
SimpleIdentifier c = _findIdentifier('cOfString');
FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
- expect(ft.toString(), '((String) → T) → List<T>');
- DartType t = e.typeParameters[0].type;
- ft = ft.substitute2([typeProvider.intType], [t]);
+ expect(ft.toString(), '<T>((String) → T) → List<T>');
+ ft = ft.instantiate([typeProvider.intType]);
expect(ft.toString(), '((String) → int) → List<int>');
}
+ void test_genericMethod_nestedCapture() {
+ _resolveTestUnit(r'''
+class C<T> {
+ /*=T*/ f/*<S>*/(/*=S*/ x) {
+ new C<S>().f/*<int>*/(3);
+ new C<S>().f; // tear-off
+ return null;
+ }
+}
+''');
+ SimpleIdentifier f = _findIdentifier('f/*<int>*/(3);');
+ expect(f.staticType.toString(), '(int) → S');
+ FunctionType ft = f.staticType;
+ expect('${ft.typeArguments}/${ft.typeParameters}', '[S, int]/[T, S]');
+
+ f = _findIdentifier('f;');
+ expect(f.staticType.toString(), '<Sâ‚€>(Sâ‚€) → S');
+ }
+
+ void test_genericMethod_nestedFunctions() {
+ _resolveTestUnit(r'''
+/*=S*/ f/*<S>*/(/*=S*/ x) {
+ g/*<S>*/(/*=S*/ x) => f;
+ return null;
+}
+''');
+ SimpleIdentifier g = _findIdentifier('f');
+ expect(g.staticType.toString(), '<S>(S) → S');
+ SimpleIdentifier f = _findIdentifier('g');
+ expect(f.staticType.toString(), '<S>(S) → dynamic');
+ }
+
void test_pseudoGeneric_max_doubleDouble() {
String code = r'''
import 'dart:math';
@@ -12261,6 +13271,22 @@
expect(declaration.initializer.propagatedType, isNull);
}
+ void test_pseudoGeneric_max_doubleDouble_prefixed() {
+ String code = r'''
+import 'dart:math' as math;
+main() {
+ var foo = math.max(1.0, 2.0);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+ expect(declaration.initializer.staticType.name, 'double');
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
void test_pseudoGeneric_max_doubleInt() {
String code = r'''
import 'dart:math';
@@ -12328,6 +13354,25 @@
expect(declaration.initializer.propagatedType, isNull);
}
+ void test_pseudoGeneric_then_prefixed() {
+ String code = r'''
+import 'dart:async' as async;
+String toString(int x) => x.toString();
+main() {
+ async.Future<int> bar = null;
+ var foo = bar.then(toString);
+}
+''';
+ _resolveTestUnit(code);
+
+ SimpleIdentifier identifier = _findIdentifier('foo');
+ VariableDeclaration declaration =
+ identifier.getAncestor((node) => node is VariableDeclaration);
+
+ expect(declaration.initializer.staticType.toString(), "Future<String>");
+ expect(declaration.initializer.propagatedType, isNull);
+ }
+
void test_ternaryOperator_null_left() {
String code = r'''
main() {
@@ -12801,108 +13846,6 @@
@reflectiveTest
class TypePropagationTest extends ResolverTestCase {
- void fail_finalPropertyInducingVariable_classMember_instance() {
- addNamedSource(
- "/lib.dart",
- r'''
-class A {
- final v = 0;
-}''');
- String code = r'''
-import 'lib.dart';
-f(A a) {
- return a.v; // marker
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_classMember_instance_inherited() {
- addNamedSource(
- "/lib.dart",
- r'''
-class A {
- final v = 0;
-}''');
- String code = r'''
-import 'lib.dart';
-class B extends A {
- m() {
- return v; // marker
- }
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
- addNamedSource(
- "/lib.dart",
- r'''
-class A {
- final v = 0;
-}''');
- String code = r'''
-import 'lib.dart';
-f(p) {
- if (p is A) {
- return p.v; // marker
- }
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_classMember_instance_unprefixed() {
- String code = r'''
-class A {
- final v = 0;
- m() {
- v; // marker
- }
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_classMember_static() {
- addNamedSource(
- "/lib.dart",
- r'''
-class A {
- static final V = 0;
-}''');
- String code = r'''
-import 'lib.dart';
-f() {
- return A.V; // marker
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_topLevelVaraible_prefixed() {
- addNamedSource("/lib.dart", "final V = 0;");
- String code = r'''
-import 'lib.dart' as p;
-f() {
- var v2 = p.V; // marker prefixed
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
- void fail_finalPropertyInducingVariable_topLevelVaraible_simple() {
- addNamedSource("/lib.dart", "final V = 0;");
- String code = r'''
-import 'lib.dart';
-f() {
- return V; // marker simple
-}''';
- _assertTypeOfMarkedExpression(
- code, typeProvider.dynamicType, typeProvider.intType);
- }
-
void fail_mergePropagatedTypesAtJoinPoint_1() {
// https://code.google.com/p/dart/issues/detail?id=19929
_assertTypeOfMarkedExpression(
@@ -13187,6 +14130,122 @@
expect(identifier.propagatedType.name, "CanvasRenderingContext2D");
}
+ void test_finalPropertyInducingVariable_classMember_instance() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f(A a) {
+ return a.v; // marker
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_classMember_instance_inherited() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+class B extends A {
+ m() {
+ return v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_classMember_instance_propagatedTarget() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ final v = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f(p) {
+ if (p is A) {
+ return p.v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_classMember_instance_unprefixed() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ String code = r'''
+class A {
+ final v = 0;
+ m() {
+ v; // marker
+ }
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_classMember_static() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource(
+ "/lib.dart",
+ r'''
+class A {
+ static final V = 0;
+}''');
+ String code = r'''
+import 'lib.dart';
+f() {
+ return A.V; // marker
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_topLevelVariable_prefixed() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource("/lib.dart", "final V = 0;");
+ String code = r'''
+import 'lib.dart' as p;
+f() {
+ var v2 = p.V; // marker prefixed
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
+ void test_finalPropertyInducingVariable_topLevelVariable_simple() {
+ // TODO(scheglov) remove after switching to the task model
+ if (!AnalysisEngine.instance.useTaskModel) return;
+ addNamedSource("/lib.dart", "final V = 0;");
+ String code = r'''
+import 'lib.dart';
+f() {
+ return V; // marker simple
+}''';
+ _assertTypeOfMarkedExpression(
+ code, typeProvider.dynamicType, typeProvider.intType);
+ }
+
void test_forEach() {
String code = r'''
main() {
@@ -13606,6 +14665,25 @@
}
}
+ void test_invocation_target_prefixed() {
+ addNamedSource(
+ '/helper.dart',
+ '''
+library helper;
+int max(int x, int y) => 0;
+''');
+ String code = '''
+import 'helper.dart' as helper;
+main() {
+ helper.max(10, 10); // marker
+}''';
+ SimpleIdentifier methodName =
+ _findMarkedIdentifier(code, "(10, 10); // marker");
+ MethodInvocation methodInvoke = methodName.parent;
+ expect(methodInvoke.methodName.staticElement, isNotNull);
+ expect(methodInvoke.methodName.propagatedElement, isNull);
+ }
+
void test_is_conditional() {
Source source = addSource(r'''
class A {}
diff --git a/pkg/analyzer/test/generated/test_all.dart b/pkg/analyzer/test/generated/test_all.dart
index fb84d46..0a9a727 100644
--- a/pkg/analyzer/test/generated/test_all.dart
+++ b/pkg/analyzer/test/generated/test_all.dart
@@ -10,6 +10,7 @@
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 @@
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();
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index 289249a..e4501be 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -20,6 +20,7 @@
runReflectiveTests(TypeSystemTest);
runReflectiveTests(StrongSubtypingTest);
runReflectiveTests(StrongAssignabilityTest);
+ runReflectiveTests(StrongGenericFunctionInferenceTest);
}
@reflectiveTest
@@ -296,6 +297,202 @@
}
@reflectiveTest
+class StrongGenericFunctionInferenceTest {
+ TypeProvider typeProvider;
+ StrongTypeSystemImpl typeSystem;
+
+ DartType get bottomType => typeProvider.bottomType;
+ InterfaceType get doubleType => typeProvider.doubleType;
+ DartType get dynamicType => typeProvider.dynamicType;
+ InterfaceType get functionType => typeProvider.functionType;
+ InterfaceType get intType => typeProvider.intType;
+ InterfaceType get iterableType => typeProvider.iterableType;
+ InterfaceType get listType => typeProvider.listType;
+ InterfaceType get numType => typeProvider.numType;
+ InterfaceType get objectType => typeProvider.objectType;
+ InterfaceType get stringType => typeProvider.stringType;
+ DartType get voidType => VoidTypeImpl.instance;
+
+ void setUp() {
+ typeProvider = new TestTypeProvider();
+ typeSystem = new StrongTypeSystemImpl();
+ }
+
+ void test_boundedByAnotherTypeParameter() {
+ // <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
+ var tFrom = _typeParameter('TFrom');
+ var tTo = _typeParameter('TTo', iterableType.substitute4([tFrom]));
+ var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+ expect(_inferCall(cast, [stringType]), [
+ stringType,
+ iterableType.substitute4([stringType])
+ ]);
+ }
+
+ void test_boundedRecursively() {
+ // class Clonable<T extends Clonable<T>>
+ ClassElementImpl clonable =
+ ElementFactory.classElement('Clonable', objectType, ['T']);
+ (clonable.typeParameters[0] as TypeParameterElementImpl).bound =
+ clonable.type;
+ // class Foo extends Clonable<Foo>
+ ClassElementImpl foo = ElementFactory.classElement('Foo', null);
+ foo.supertype = clonable.type.substitute4([foo.type]);
+
+ // <S extends Clonable<S>>
+ var s = _typeParameter('S');
+ (s.element as TypeParameterElementImpl).bound =
+ clonable.type.substitute4([s]);
+ // (S, S) -> S
+ var clone = _functionType([s], [s, s], s);
+ expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
+
+ // Something invalid...
+ expect(_inferCall(clone, [stringType, numType]), [
+ clonable.type.substitute4([dynamicType])
+ ]);
+ }
+
+ void test_genericCastFunction() {
+ // <TFrom, TTo>(TFrom) -> TTo
+ var tFrom = _typeParameter('TFrom');
+ var tTo = _typeParameter('TTo');
+ var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+ expect(_inferCall(cast, [intType]), [intType, dynamicType]);
+ }
+
+ void test_genericCastFunctionWithUpperBound() {
+ // <TFrom, TTo extends TFrom>(TFrom) -> TTo
+ var tFrom = _typeParameter('TFrom');
+ var tTo = _typeParameter('TTo', tFrom);
+ var cast = _functionType([tFrom, tTo], [tFrom], tTo);
+ expect(_inferCall(cast, [intType]), [intType, intType]);
+ }
+
+ void test_parametersToFunctionParam() {
+ // <T>(f(T t)) -> T
+ var t = _typeParameter('T');
+ var cast = _functionType([
+ t
+ ], [
+ _functionType([], [t], dynamicType)
+ ], t);
+ expect(
+ _inferCall(cast, [
+ _functionType([], [numType], dynamicType)
+ ]),
+ [numType]);
+ }
+
+ void test_parametersUseLeastUpperBound() {
+ // <T>(T x, T y) -> T
+ var t = _typeParameter('T');
+ var cast = _functionType([t], [t, t], t);
+ expect(_inferCall(cast, [intType, doubleType]), [numType]);
+ }
+
+ void test_parameterTypeUsesUpperBound() {
+ // <T extends num>(T) -> dynamic
+ var t = _typeParameter('T', numType);
+ var f = _functionType([t], [t], dynamicType);
+ expect(_inferCall(f, [intType]), [intType]);
+ }
+
+ void test_returnFunctionWithGenericParameter() {
+ // <T>(T -> T) -> (T -> void)
+ var t = _typeParameter('T');
+ var f = _functionType([
+ t
+ ], [
+ _functionType([], [t], t)
+ ], _functionType([], [t], voidType));
+ expect(
+ _inferCall(f, [
+ _functionType([], [numType], intType)
+ ]),
+ [numType]);
+ }
+
+ void test_returnFunctionWithGenericParameterAndReturn() {
+ // <T>(T -> T) -> (T -> T)
+ var t = _typeParameter('T');
+ var f = _functionType([
+ t
+ ], [
+ _functionType([], [t], t)
+ ], _functionType([], [t], t));
+ expect(
+ _inferCall(f, [
+ _functionType([], [numType], intType)
+ ]),
+ [numType]);
+ }
+
+ void test_returnFunctionWithGenericReturn() {
+ // <T>(T -> T) -> (() -> T)
+ var t = _typeParameter('T');
+ var f = _functionType([
+ t
+ ], [
+ _functionType([], [t], t)
+ ], _functionType([], [], t));
+ expect(
+ _inferCall(f, [
+ _functionType([], [numType], intType)
+ ]),
+ [intType]);
+ }
+
+ void test_unifyParametersToFunctionParam() {
+ // <T>(f(T t), g(T t)) -> T
+ var t = _typeParameter('T');
+ var cast = _functionType([
+ t
+ ], [
+ _functionType([], [t], dynamicType),
+ _functionType([], [t], dynamicType)
+ ], t);
+ expect(
+ _inferCall(cast, [
+ _functionType([], [intType], dynamicType),
+ _functionType([], [doubleType], dynamicType)
+ ]),
+ [dynamicType]);
+ }
+
+ void test_unusedReturnTypeIsDynamic() {
+ // <T>() -> T
+ var t = _typeParameter('T');
+ var f = _functionType([t], [], t);
+ expect(_inferCall(f, []), [dynamicType]);
+ }
+
+ void test_unusedReturnTypeWithUpperBound() {
+ // <T extends num>() -> T
+ var t = _typeParameter('T', numType);
+ var f = _functionType([t], [], t);
+ expect(_inferCall(f, []), [numType]);
+ }
+
+ FunctionTypeImpl _functionType(
+ List<DartType> typeParams, List<DartType> params, DartType result) {
+ FunctionElementImpl f = ElementFactory.functionElement8(params, result);
+ f.typeParameters =
+ new List<TypeParameterElement>.from(typeParams.map((t) => t.element));
+ return f.type = new FunctionTypeImpl(f);
+ }
+
+ List<DartType> _inferCall(FunctionTypeImpl ft, List<DartType> arguments) {
+ FunctionType inferred = typeSystem.inferCallFromArguments(
+ typeProvider, ft, ft.parameters.map((p) => p.type).toList(), arguments);
+ return inferred.typeArguments;
+ }
+
+ TypeParameterType _typeParameter(String name, [DartType bound]) =>
+ ElementFactory.typeParameterWithType(name, bound).type;
+}
+
+@reflectiveTest
class StrongSubtypingTest {
TypeProvider typeProvider;
TypeSystem typeSystem;
@@ -478,6 +675,13 @@
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);
diff --git a/pkg/analyzer/test/source/package_map_provider_test.dart b/pkg/analyzer/test/source/package_map_provider_test.dart
index af5bedf..3701630 100644
--- a/pkg/analyzer/test/source/package_map_provider_test.dart
+++ b/pkg/analyzer/test/source/package_map_provider_test.dart
@@ -8,119 +8,132 @@
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/package_map_provider.dart';
import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:unittest/unittest.dart';
+import '../reflective_tests.dart';
import '../utils.dart';
main() {
initializeTestEnvironment();
+ runReflectiveTests(PubPackageMapProviderTest);
+}
- group('PubPackageMapProvider', () {
- group('parsePackageMap', () {
- MemoryResourceProvider resourceProvider;
- PubPackageMapProvider packageMapProvider;
- const String projectPath = '/path/to/project';
- Folder projectFolder;
+@reflectiveTest
+class PubPackageMapProviderTest {
+ static const String projectPath = '/path/to/project';
- setUp(() {
- resourceProvider = new MemoryResourceProvider();
- packageMapProvider = new PubPackageMapProvider(
- resourceProvider, DirectoryBasedDartSdk.defaultSdk);
- projectFolder = resourceProvider.newFolder(projectPath);
- });
+ DartSdk sdk = DirectoryBasedDartSdk.defaultSdk;
+ MemoryResourceProvider resourceProvider;
+ PubPackageMapProvider packageMapProvider;
+ Folder projectFolder;
- PackageMapInfo parsePackageMap(Object obj) {
- return packageMapProvider.parsePackageMap(obj, projectFolder);
- }
+ PackageMapInfo parsePackageMap(Map obj) {
+ return packageMapProvider.parsePackageMap(obj, projectFolder);
+ }
- test('normal folder', () {
- String packageName = 'foo';
- String folderPath = '/path/to/folder';
- resourceProvider.newFolder(folderPath);
- Map<String, List<Folder>> result = parsePackageMap({
- 'packages': {packageName: folderPath}
- }).packageMap;
- expect(result, hasLength(1));
- expect(result.keys, contains(packageName));
- expect(result[packageName], hasLength(1));
- expect(result[packageName][0], new isInstanceOf<Folder>());
- expect(result[packageName][0].path, equals(folderPath));
- });
+ void setUp() {
+ resourceProvider = new MemoryResourceProvider();
+ packageMapProvider = new PubPackageMapProvider(resourceProvider, sdk);
+ projectFolder = resourceProvider.newFolder(projectPath);
+ }
- test("don't ignore nonexistent folder", () {
- String packageName = 'foo';
- String folderPath = '/path/to/folder';
- Map<String, List<Folder>> result = parsePackageMap({
- 'packages': {packageName: folderPath}
- }).packageMap;
- expect(result, hasLength(1));
- expect(result.keys, contains(packageName));
- expect(result[packageName], hasLength(1));
- expect(result[packageName][0], new isInstanceOf<Folder>());
- expect(result[packageName][0].path, equals(folderPath));
- });
-
- test('package maps to list', () {
- String packageName = 'foo';
- String folderPath1 = '/path/to/folder1';
- String folderPath2 = '/path/to/folder2';
- resourceProvider.newFolder(folderPath1);
- resourceProvider.newFolder(folderPath2);
- Map<String, List<Folder>> result = parsePackageMap({
- 'packages': {
- packageName: [folderPath1, folderPath2]
- }
- }).packageMap;
- expect(result, hasLength(1));
- expect(result.keys, contains(packageName));
- expect(result[packageName], hasLength(2));
- for (int i = 0; i < 2; i++) {
- expect(result[packageName][i], new isInstanceOf<Folder>());
- expect(result[packageName][i].path, isIn([folderPath1, folderPath2]));
- }
- });
-
- test('Handle dependencies', () {
- String path1 = '/path/to/folder1/pubspec.lock';
- String path2 = '/path/to/folder2/pubspec.lock';
- resourceProvider.newFile(path1, '...');
- resourceProvider.newFile(path2, '...');
- Set<String> dependencies = parsePackageMap({
- 'packages': {},
- 'input_files': [path1, path2]
- }).dependencies;
- expect(dependencies, hasLength(2));
- expect(dependencies, contains(path1));
- expect(dependencies, contains(path2));
- });
-
- test('Relative path in packages', () {
- String packagePath = '/path/to/package';
- String relativePackagePath = '../package';
- String packageName = 'foo';
- resourceProvider.newFolder(projectPath);
- resourceProvider.newFolder(packagePath);
- Map<String, List<Folder>> result = parsePackageMap({
- 'packages': {
- packageName: [relativePackagePath]
- }
- }).packageMap;
- expect(result[packageName][0].path, equals(packagePath));
- });
-
- test('Relative path in dependencies', () {
- String dependencyPath = '/path/to/pubspec.lock';
- String relativeDependencyPath = '../pubspec.lock';
- resourceProvider.newFolder(projectPath);
- resourceProvider.newFile(dependencyPath, 'contents');
- Set<String> dependencies = parsePackageMap({
- 'packages': {},
- 'input_files': [relativeDependencyPath]
- }).dependencies;
- expect(dependencies, hasLength(1));
- expect(dependencies, contains(dependencyPath));
- });
+ void test_computePackageMap_noLockFile() {
+ packageMapProvider =
+ new PubPackageMapProvider(resourceProvider, sdk, (Folder folder) {
+ fail('Unexpected "pub list" invocation');
});
- });
+ PackageMapInfo info = packageMapProvider.computePackageMap(projectFolder);
+ expect(info.packageMap, isNull);
+ expect(info.dependencies, unorderedEquals(['$projectPath/pubspec.lock']));
+ }
+
+ void test_parsePackageMap_dontIgnoreNonExistingFolder() {
+ String packageName = 'foo';
+ String folderPath = '/path/to/folder';
+ Map<String, List<Folder>> result = parsePackageMap({
+ 'packages': {packageName: folderPath}
+ }).packageMap;
+ expect(result, hasLength(1));
+ expect(result.keys, contains(packageName));
+ expect(result[packageName], hasLength(1));
+ expect(result[packageName][0], new isInstanceOf<Folder>());
+ expect(result[packageName][0].path, equals(folderPath));
+ }
+
+ void test_parsePackageMap_handleDependencies() {
+ String path1 = '/path/to/folder1/pubspec.lock';
+ String path2 = '/path/to/folder2/pubspec.lock';
+ resourceProvider.newFile(path1, '...');
+ resourceProvider.newFile(path2, '...');
+ Set<String> dependencies = parsePackageMap({
+ 'packages': {},
+ 'input_files': [path1, path2]
+ }).dependencies;
+ expect(dependencies, hasLength(2));
+ expect(dependencies, contains(path1));
+ expect(dependencies, contains(path2));
+ }
+
+ void test_parsePackageMap_normalFolder() {
+ String packageName = 'foo';
+ String folderPath = '/path/to/folder';
+ resourceProvider.newFolder(folderPath);
+ Map<String, List<Folder>> result = parsePackageMap({
+ 'packages': {packageName: folderPath}
+ }).packageMap;
+ expect(result, hasLength(1));
+ expect(result.keys, contains(packageName));
+ expect(result[packageName], hasLength(1));
+ expect(result[packageName][0], new isInstanceOf<Folder>());
+ expect(result[packageName][0].path, equals(folderPath));
+ }
+
+ void test_parsePackageMap_packageMapsToList() {
+ String packageName = 'foo';
+ String folderPath1 = '/path/to/folder1';
+ String folderPath2 = '/path/to/folder2';
+ resourceProvider.newFolder(folderPath1);
+ resourceProvider.newFolder(folderPath2);
+ Map<String, List<Folder>> result = parsePackageMap({
+ 'packages': {
+ packageName: [folderPath1, folderPath2]
+ }
+ }).packageMap;
+ expect(result, hasLength(1));
+ expect(result.keys, contains(packageName));
+ expect(result[packageName], hasLength(2));
+ for (int i = 0; i < 2; i++) {
+ expect(result[packageName][i], new isInstanceOf<Folder>());
+ expect(result[packageName][i].path, isIn([folderPath1, folderPath2]));
+ }
+ }
+
+ void test_parsePackageMap_relativePahInPackages() {
+ String packagePath = '/path/to/package';
+ String relativePackagePath = '../package';
+ String packageName = 'foo';
+ resourceProvider.newFolder(projectPath);
+ resourceProvider.newFolder(packagePath);
+ Map<String, List<Folder>> result = parsePackageMap({
+ 'packages': {
+ packageName: [relativePackagePath]
+ }
+ }).packageMap;
+ expect(result[packageName][0].path, equals(packagePath));
+ }
+
+ void test_parsePackageMap_relativePathInDependencies() {
+ String dependencyPath = '/path/to/pubspec.lock';
+ String relativeDependencyPath = '../pubspec.lock';
+ resourceProvider.newFolder(projectPath);
+ resourceProvider.newFile(dependencyPath, 'contents');
+ Set<String> dependencies = parsePackageMap({
+ 'packages': {},
+ 'input_files': [relativeDependencyPath]
+ }).dependencies;
+ expect(dependencies, hasLength(1));
+ expect(dependencies, contains(dependencyPath));
+ }
}
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index 75c156a..0962474 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -961,12 +961,31 @@
expect(createPartition(), isNotNull);
}
+ void test_dispose() {
+ CachePartition partition = createPartition();
+ Source source1 = new TestSource('/1.dart');
+ Source source2 = new TestSource('/2.dart');
+ CacheEntry entry1 = new CacheEntry(source1);
+ CacheEntry entry2 = new CacheEntry(source2);
+ // add two sources
+ partition.put(entry1);
+ partition.put(entry2);
+ expect(partition.entryMap, hasLength(2));
+ expect(partition.pathToSource, hasLength(2));
+ expect(partition.sources, unorderedEquals([source1, source2]));
+ // dispose, no sources
+ partition.dispose();
+ expect(partition.entryMap, isEmpty);
+ expect(partition.pathToSource, isEmpty);
+ expect(partition.sources, isEmpty);
+ }
+
void test_entrySet() {
CachePartition partition = createPartition();
AnalysisTarget target = new TestSource();
CacheEntry entry = new CacheEntry(target);
partition.put(entry);
- Map<AnalysisTarget, CacheEntry> entryMap = partition.map;
+ Map<AnalysisTarget, CacheEntry> entryMap = partition.entryMap;
expect(entryMap, hasLength(1));
AnalysisTarget entryKey = entryMap.keys.first;
expect(entryKey, target);
diff --git a/pkg/analyzer/test/src/context/mock_sdk.dart b/pkg/analyzer/test/src/context/mock_sdk.dart
index 121fb5d..ad1c2f6 100644
--- a/pkg/analyzer/test/src/context/mock_sdk.dart
+++ b/pkg/analyzer/test/src/context/mock_sdk.dart
@@ -86,6 +86,11 @@
abstract class Iterable<E> {
Iterator<E> get iterator;
bool get isEmpty;
+
+ Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
+
+ /*=R*/ fold/*<R>*/(/*=R*/ initialValue,
+ /*=R*/ combine(/*=R*/ previousValue, E element));
}
abstract class List<E> implements Iterable<E> {
@@ -123,7 +128,10 @@
class Future<T> {
factory Future.delayed(Duration duration, [T computation()]) => null;
factory Future.value([value]) => null;
- static Future wait(List<Future> futures) => null;
+
+ static Future<List</*<T>*/> wait/*<T>*/(
+ Iterable<Future/*<T>*/> futures) => null;
+ Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
}
''',
const <_MockSdkFile>[
@@ -162,11 +170,14 @@
'/lib/math/math.dart',
'''
library dart.math;
+
const double E = 2.718281828459045;
const double PI = 3.1415926535897932;
const double LN10 = 2.302585092994046;
-num min(num a, num b) => 0;
-num max(num a, num b) => 0;
+
+num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+
external double cos(num x);
external double sin(num x);
external double sqrt(num x);
diff --git a/pkg/analyzer/test/src/summary/summary_test.dart b/pkg/analyzer/test/src/summary/summary_test.dart
index e0cfbca..be2844e 100644
--- a/pkg/analyzer/test/src/summary/summary_test.dart
+++ b/pkg/analyzer/test/src/summary/summary_test.dart
@@ -209,8 +209,8 @@
String relativeUri, String expectedName,
{String expectedPrefix,
bool allowTypeParameters: false,
- PrelinkedReferenceKind expectedKind:
- PrelinkedReferenceKind.classOrEnum}) {
+ PrelinkedReferenceKind expectedKind: PrelinkedReferenceKind.classOrEnum,
+ int expectedUnit: 0}) {
expect(typeRef, new isInstanceOf<UnlinkedTypeRef>());
expect(typeRef.paramReference, 0);
int index = typeRef.reference;
@@ -239,6 +239,7 @@
}
}
expect(referenceResolution.kind, expectedKind);
+ expect(referenceResolution.unit, expectedUnit);
}
/**
@@ -1658,7 +1659,8 @@
otherDeclarations: 'library my.lib; import "a.dart";'),
absUri('/a.dart'),
'a.dart',
- 'C');
+ 'C',
+ expectedUnit: 1);
}
test_type_reference_to_imported_part_with_prefix() {
@@ -1670,7 +1672,8 @@
absUri('/a.dart'),
'a.dart',
'C',
- expectedPrefix: 'p');
+ expectedPrefix: 'p',
+ expectedUnit: 1);
}
test_type_reference_to_internal_class() {
@@ -1699,7 +1702,8 @@
otherDeclarations: 'library my.lib; part "a.dart";'),
null,
null,
- 'C');
+ 'C',
+ expectedUnit: 1);
}
test_type_reference_to_nonexistent_file_via_prefix() {
@@ -1723,7 +1727,7 @@
// The referenced unit should be 2, since unit 0 is a.dart and unit 1 is
// b.dart. a.dart and b.dart are counted even though nothing is imported
// from them.
- checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C');
+ checkTypeRef(typeRef, absUri('/a.dart'), 'a.dart', 'C', expectedUnit: 2);
}
test_type_unresolved() {
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index c0ad43b..dcb6980 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -44,6 +44,7 @@
runReflectiveTests(ComputeConstantValueTaskTest);
runReflectiveTests(ComputeInferableStaticVariableDependenciesTaskTest);
runReflectiveTests(ComputeLibraryCycleTaskTest);
+ runReflectiveTests(ComputePropagableVariableDependenciesTaskTest);
runReflectiveTests(ContainingLibrariesTaskTest);
runReflectiveTests(DartErrorsTaskTest);
runReflectiveTests(ErrorFilterTest);
@@ -59,6 +60,8 @@
runReflectiveTests(LibraryUnitErrorsTaskTest);
runReflectiveTests(ParseDartTaskTest);
runReflectiveTests(PartiallyResolveUnitReferencesTaskTest);
+ runReflectiveTests(PropagateVariableTypesInUnitTaskTest);
+ runReflectiveTests(PropagateVariableTypeTaskTest);
runReflectiveTests(ResolveInstanceFieldsInUnitTaskTest);
runReflectiveTests(ResolveLibraryTypeNamesTaskTest);
runReflectiveTests(ResolveUnitTaskTest);
@@ -92,6 +95,8 @@
new isInstanceOf<ComputeConstantValueTask>();
isInstanceOf isComputeInferableStaticVariableDependenciesTask =
new isInstanceOf<ComputeInferableStaticVariableDependenciesTask>();
+isInstanceOf isComputePropagableVariableDependenciesTask =
+ new isInstanceOf<ComputePropagableVariableDependenciesTask>();
isInstanceOf isContainingLibrariesTask =
new isInstanceOf<ContainingLibrariesTask>();
isInstanceOf isDartErrorsTask = new isInstanceOf<DartErrorsTask>();
@@ -116,6 +121,10 @@
isInstanceOf isParseDartTask = new isInstanceOf<ParseDartTask>();
isInstanceOf isPartiallyResolveUnitReferencesTask =
new isInstanceOf<PartiallyResolveUnitReferencesTask>();
+isInstanceOf isPropagateVariableTypesInUnitTask =
+ new isInstanceOf<PropagateVariableTypesInUnitTask>();
+isInstanceOf isPropagateVariableTypeTask =
+ new isInstanceOf<PropagateVariableTypeTask>();
isInstanceOf isResolveLibraryTypeNamesTask =
new isInstanceOf<ResolveLibraryTypeNamesTask>();
isInstanceOf isResolveUnitTask = new isInstanceOf<ResolveUnitTask>();
@@ -1275,7 +1284,7 @@
// should be set to the same error state.
for (String otherVariableName in otherVariables) {
PropertyInducingElement otherVariableElement =
- _findVariable(unit, otherVariableName);
+ AstFinder.getTopLevelVariableElement(unit, otherVariableName);
_expectCircularityError((otherVariableElement
as TopLevelVariableElementImpl).evaluationResult);
}
@@ -1289,7 +1298,8 @@
EvaluationResultImpl _evaluateConstant(
CompilationUnit unit, String variableName) {
// Find the element for the given constant.
- PropertyInducingElement variableElement = _findVariable(unit, variableName);
+ PropertyInducingElement variableElement =
+ AstFinder.getTopLevelVariableElement(unit, variableName);
// Now compute the value of the constant.
computeResult(variableElement, CONSTANT_VALUE,
matcher: isComputeConstantValueTask);
@@ -1307,13 +1317,6 @@
CompileTimeErrorCode.RECURSIVE_COMPILE_TIME_CONSTANT);
}
- PropertyInducingElement _findVariable(
- CompilationUnit unit, String variableName) {
- // Find the element for the given constant.
- return unit.element.topLevelVariables.firstWhere(
- (TopLevelVariableElement variable) => variable.name == variableName);
- }
-
CompilationUnit _resolveSource(Source source) {
LibrarySpecificUnit librarySpecificUnit =
new LibrarySpecificUnit(source, source);
@@ -1761,6 +1764,134 @@
}
@reflectiveTest
+class ComputePropagableVariableDependenciesTaskTest
+ extends _AbstractDartTaskTest {
+ test_perform_instanceField() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+class A {
+ final a = a1 + a2 + a3 + a4 + B.b1 + B.b2 + B.b3 + B.b4;
+ static const a1 = 1;
+ final a2 = 2;
+ final a3;
+ var a4 = 4;
+}
+class B {
+ static const b1 = 1;
+ static final b2 = 2;
+ static final b3;
+ static var b4 = 4;
+}
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ FieldElement elementA = AstFinder.getFieldInClassElement(unit, 'A', 'a');
+ // compute
+ computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+ matcher: isComputePropagableVariableDependenciesTask);
+ // verify
+ expect(outputs, hasLength(1));
+ List<VariableElement> dependencies =
+ outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+ expect(
+ dependencies,
+ unorderedEquals([
+ AstFinder.getFieldInClassElement(unit, 'A', 'a1'),
+ AstFinder.getFieldInClassElement(unit, 'A', 'a2'),
+ AstFinder.getFieldInClassElement(unit, 'B', 'b1'),
+ AstFinder.getFieldInClassElement(unit, 'B', 'b2')
+ ]));
+ }
+
+ test_perform_topLevel() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+const a = d1 + d2 + d3 + d4;
+const d1 = 1;
+final d2 = 2;
+final d3;
+var d4 = 4;
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement elementA =
+ AstFinder.getTopLevelVariableElement(unit, 'a');
+ // compute
+ computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+ matcher: isComputePropagableVariableDependenciesTask);
+ // verify
+ expect(outputs, hasLength(1));
+ List<VariableElement> dependencies =
+ outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+ expect(
+ dependencies,
+ unorderedEquals([
+ AstFinder.getTopLevelVariableElement(unit, 'd1'),
+ AstFinder.getTopLevelVariableElement(unit, 'd2')
+ ]));
+ }
+
+ test_perform_topLevel_ignoreLocal() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+final a = () {
+ const b = 2;
+ const c = 3;
+ return b + c;
+}() + d;
+final d = 4;
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement elementA =
+ AstFinder.getTopLevelVariableElement(unit, 'a');
+ // compute
+ computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+ matcher: isComputePropagableVariableDependenciesTask);
+ // verify
+ expect(outputs, hasLength(1));
+ List<VariableElement> dependencies =
+ outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+ expect(dependencies,
+ unorderedEquals([AstFinder.getTopLevelVariableElement(unit, 'd')]));
+ }
+
+ test_perform_topLevel_withoutSpaceAfterType() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+const List<int>a=[b, c];
+const b = 1;
+const c = 2;
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement elementA =
+ AstFinder.getTopLevelVariableElement(unit, 'a');
+ // compute
+ computeResult(elementA, PROPAGABLE_VARIABLE_DEPENDENCIES,
+ matcher: isComputePropagableVariableDependenciesTask);
+ // verify
+ expect(outputs, hasLength(1));
+ List<VariableElement> dependencies =
+ outputs[PROPAGABLE_VARIABLE_DEPENDENCIES];
+ expect(
+ dependencies,
+ unorderedEquals([
+ AstFinder.getTopLevelVariableElement(unit, 'b'),
+ AstFinder.getTopLevelVariableElement(unit, 'c')
+ ]));
+ }
+}
+
+@reflectiveTest
class ContainingLibrariesTaskTest extends _AbstractDartTaskTest {
test_perform_definingCompilationUnit() {
AnalysisTarget library = newSource('/test.dart', 'library test;');
@@ -1831,6 +1962,32 @@
}
@reflectiveTest
+class ErrorFilterTest extends _AbstractDartTaskTest {
+ @override
+ setUp() {
+ super.setUp();
+ context.setConfigurationData(CONFIGURED_ERROR_FILTERS, [
+ (AnalysisError error) => error.errorCode.name == 'INVALID_ASSIGNMENT'
+ ]);
+ }
+
+ test_error_filters() {
+ AnalysisTarget library = newSource(
+ '/test.dart',
+ '''
+main() {
+ int x = ""; // INVALID_ASSIGNMENT (suppressed)
+ // UNUSED_LOCAL_VARIABLE
+}''');
+ computeResult(library, DART_ERRORS, matcher: isDartErrorsTask);
+ expect(outputs, hasLength(1));
+ List<AnalysisError> errors = outputs[DART_ERRORS];
+ expect(errors, hasLength(1));
+ expect(errors.first.errorCode, HintCode.UNUSED_LOCAL_VARIABLE);
+ }
+}
+
+@reflectiveTest
class EvaluateUnitConstantsTaskTest extends _AbstractDartTaskTest {
test_perform() {
Source source = newSource(
@@ -1846,9 +2003,9 @@
const x = const C();
''');
LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
- computeResult(target, RESOLVED_UNIT10,
+ computeResult(target, RESOLVED_UNIT11,
matcher: isEvaluateUnitConstantsTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT10];
+ CompilationUnit unit = outputs[RESOLVED_UNIT11];
CompilationUnitElement unitElement = unit.element;
expect(
(unitElement.types[0].constructors[0] as ConstructorElementImpl)
@@ -2241,30 +2398,6 @@
}
@reflectiveTest
-class ErrorFilterTest extends _AbstractDartTaskTest {
- @override
- setUp() {
- super.setUp();
- context.setConfigurationData(CONFIGURED_ERROR_FILTERS, [
- (AnalysisError error) => error.errorCode.name == 'INVALID_ASSIGNMENT'
- ]);
- }
-
- test_error_filters() {
- AnalysisTarget library = newSource('/test.dart', '''
-main() {
- int x = ""; // INVALID_ASSIGNMENT (suppressed)
- // UNUSED_LOCAL_VARIABLE
-}''');
- computeResult(library, DART_ERRORS, matcher: isDartErrorsTask);
- expect(outputs, hasLength(1));
- List<AnalysisError> errors = outputs[DART_ERRORS];
- expect(errors, hasLength(1));
- expect(errors.first.errorCode, HintCode.UNUSED_LOCAL_VARIABLE);
- }
-}
-
-@reflectiveTest
class GenerateLintsTaskTest extends _AbstractDartTaskTest {
void enableLints() {
AnalysisOptionsImpl options = context.analysisOptions;
@@ -2337,14 +2470,14 @@
class Y {}
class Z {}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8,
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9,
matcher: isInferInstanceMembersInUnitTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
- VariableDeclaration field = getFieldInClass(unit, 'B', 'f');
- MethodDeclaration method = getMethodInClass(unit, 'B', 'm');
- DartType typeX = getClass(unit, 'X').element.type;
- DartType typeY = getClass(unit, 'Y').element.type;
- DartType typeZ = getClass(unit, 'Z').element.type;
+ CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ VariableDeclaration field = AstFinder.getFieldInClass(unit, 'B', 'f');
+ MethodDeclaration method = AstFinder.getMethodInClass(unit, 'B', 'm');
+ DartType typeX = AstFinder.getClass(unit, 'X').element.type;
+ DartType typeY = AstFinder.getClass(unit, 'Y').element.type;
+ DartType typeZ = AstFinder.getClass(unit, 'Z').element.type;
expect(field.element.type, typeX);
expect(method.element.returnType, typeY);
@@ -2371,16 +2504,19 @@
}
''');
computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8,
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9,
matcher: isInferInstanceMembersInUnitTask);
- CompilationUnit firstUnit = outputs[RESOLVED_UNIT8];
+ CompilationUnit firstUnit = outputs[RESOLVED_UNIT9];
computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
- CompilationUnit secondUnit = outputs[RESOLVED_UNIT8];
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
+ CompilationUnit secondUnit = outputs[RESOLVED_UNIT9];
- VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a');
- VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b');
- VariableDeclaration variableC = getFieldInClass(secondUnit, 'M', 'c');
+ VariableDeclaration variableA =
+ AstFinder.getTopLevelVariable(firstUnit, 'a');
+ VariableDeclaration variableB =
+ AstFinder.getTopLevelVariable(secondUnit, 'b');
+ VariableDeclaration variableC =
+ AstFinder.getFieldInClass(secondUnit, 'M', 'c');
InterfaceType stringType = context.typeProvider.stringType;
expect(variableA.element.type, stringType);
@@ -2400,10 +2536,12 @@
String field = topLevel;
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
- CompilationUnit unit = outputs[RESOLVED_UNIT8];
- VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
- VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
+ CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ VariableDeclaration topLevelDecl =
+ AstFinder.getTopLevelVariable(unit, 'topLevel');
+ VariableDeclaration fieldDecl =
+ AstFinder.getFieldInClass(unit, 'C', 'field');
VariableElement topLevel = topLevelDecl.name.staticElement;
VariableElement field = fieldDecl.name.staticElement;
@@ -2425,10 +2563,10 @@
static const X = "";
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
matcher: isInferStaticVariableTypesInUnitTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT6];
- VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
+ CompilationUnit unit = outputs[RESOLVED_UNIT7];
+ VariableDeclaration declaration = AstFinder.getFieldInClass(unit, 'M', 'X');
InterfaceType stringType = context.typeProvider.stringType;
expect(declaration.element.type, stringType);
}
@@ -2444,7 +2582,7 @@
return xSquared;
};
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
matcher: isInferStaticVariableTypesInUnitTask);
}
@@ -2467,17 +2605,20 @@
class M {}
''');
computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT6,
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT7,
matcher: isInferStaticVariableTypesInUnitTask);
- CompilationUnit firstUnit = outputs[RESOLVED_UNIT6];
+ CompilationUnit firstUnit = outputs[RESOLVED_UNIT7];
computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT6);
- CompilationUnit secondUnit = outputs[RESOLVED_UNIT6];
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT7);
+ CompilationUnit secondUnit = outputs[RESOLVED_UNIT7];
- VariableDeclaration variableA = getTopLevelVariable(firstUnit, 'a');
- VariableDeclaration variableB = getTopLevelVariable(secondUnit, 'b');
- VariableDeclaration variableC = getTopLevelVariable(firstUnit, 'c');
- ClassDeclaration classM = getClass(secondUnit, 'M');
+ VariableDeclaration variableA =
+ AstFinder.getTopLevelVariable(firstUnit, 'a');
+ VariableDeclaration variableB =
+ AstFinder.getTopLevelVariable(secondUnit, 'b');
+ VariableDeclaration variableC =
+ AstFinder.getTopLevelVariable(firstUnit, 'c');
+ ClassDeclaration classM = AstFinder.getClass(secondUnit, 'M');
DartType typeM = classM.element.type;
expect(variableA.element.type, typeM);
@@ -2498,9 +2639,9 @@
return 1 + X;
};
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT7,
matcher: isInferStaticVariableTypesInUnitTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT6];
+ CompilationUnit unit = outputs[RESOLVED_UNIT7];
TopLevelVariableDeclaration declaration = unit.declarations[1];
FunctionExpression function =
declaration.variables.variables[0].initializer;
@@ -2524,7 +2665,8 @@
''');
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableDeclaration declaration = getFieldInClass(unit, 'C', 'field');
+ VariableDeclaration declaration =
+ AstFinder.getFieldInClass(unit, 'C', 'field');
VariableElement variable = declaration.name.staticElement;
InferStaticVariableTypeTask inferTask =
new InferStaticVariableTypeTask(task.context, variable);
@@ -2539,7 +2681,8 @@
''');
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableDeclaration declaration = getTopLevelVariable(unit, 'topLevel');
+ VariableDeclaration declaration =
+ AstFinder.getTopLevelVariable(unit, 'topLevel');
VariableElement variable = declaration.name.staticElement;
InferStaticVariableTypeTask inferTask =
new InferStaticVariableTypeTask(task.context, variable);
@@ -2558,8 +2701,10 @@
''');
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel3');
- VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field3');
+ VariableDeclaration topLevelDecl =
+ AstFinder.getTopLevelVariable(unit, 'topLevel3');
+ VariableDeclaration fieldDecl =
+ AstFinder.getFieldInClass(unit, 'C', 'field3');
VariableElement topLevel = topLevelDecl.name.staticElement;
VariableElement field = fieldDecl.name.staticElement;
@@ -2584,9 +2729,9 @@
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
VariableElement topLevel =
- getTopLevelVariable(unit, 'topLevel').name.staticElement;
+ AstFinder.getTopLevelVariable(unit, 'topLevel').name.staticElement;
VariableElement field =
- getFieldInClass(unit, 'C', 'field').name.staticElement;
+ AstFinder.getFieldInClass(unit, 'C', 'field').name.staticElement;
computeResult(field, INFERRED_STATIC_VARIABLE,
matcher: isInferStaticVariableTypeTask);
@@ -2607,9 +2752,11 @@
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
VariableElement piFirst =
- getTopLevelVariable(unit, 'piFirst').name.staticElement;
- VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
- VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
+ AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement;
+ VariableElement pi =
+ AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement;
+ VariableElement tau =
+ AstFinder.getTopLevelVariable(unit, 'tau').name.staticElement;
computeResult(piFirst, INFERRED_STATIC_VARIABLE,
matcher: isInferStaticVariableTypeTask);
@@ -2627,7 +2774,8 @@
''');
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement;
+ VariableElement a =
+ AstFinder.getTopLevelVariable(unit, 'a').name.staticElement;
computeResult(a, INFERRED_STATIC_VARIABLE,
matcher: isInferStaticVariableTypeTask);
@@ -2643,7 +2791,8 @@
''');
computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
CompilationUnit unit = outputs[RESOLVED_UNIT5];
- VariableElement a = getTopLevelVariable(unit, 'a').name.staticElement;
+ VariableElement a =
+ AstFinder.getTopLevelVariable(unit, 'a').name.staticElement;
computeResult(a, INFERRED_STATIC_VARIABLE,
matcher: isInferStaticVariableTypeTask);
@@ -2764,6 +2913,13 @@
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;
@@ -2842,35 +2998,36 @@
@reflectiveTest
class PartiallyResolveUnitReferencesTaskTest extends _AbstractDartTaskTest {
- test_perform() {
+ test_perform_propagable() {
enableStrongMode();
Source source = newSource(
'/test.dart',
'''
-int a = b;
-int b = c;
-var d = 0;
-class A {}
+const t1 = 1;
+final t2 = 2;
+var t3 = 3;
+final t4;
class C {
- static final f = '';
- var g = 0;
+ static const fs1 = 1;
+ static final fs2 = 2;
+ static var fs3 = 3;
+ static final fs4;
+ const fi1 = 1;
+ final fi2 = 2;
+ var fi3 = 3;
+ final fi4;
}
''');
LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
- computeResult(target, RESOLVED_UNIT5,
+ computeResult(target, PROPAGABLE_VARIABLES_IN_UNIT,
matcher: isPartiallyResolveUnitReferencesTask);
- // Test the outputs
- expect(outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT], hasLength(4));
- CompilationUnit unit = outputs[RESOLVED_UNIT5];
- expect(unit, same(outputs[RESOLVED_UNIT5]));
- // Test the state of the AST
- TopLevelVariableDeclaration a = unit.declarations[0];
- VariableDeclaration variableA = a.variables.variables[0];
- SimpleIdentifier initializer = variableA.initializer;
- expect(initializer.staticElement, isNotNull);
+ // PROPAGABLE_VARIABLES_IN_UNIT
+ List<VariableElement> variables = outputs[PROPAGABLE_VARIABLES_IN_UNIT];
+ expect(variables.map((v) => v.displayName),
+ unorderedEquals(['t1', 't2', 'fs1', 'fs2', 'fi1', 'fi2']));
}
- test_perform_importExport() {
+ test_perform_strong_importExport() {
newSource(
'/a.dart',
'''
@@ -2911,7 +3068,40 @@
expect(methodElement, isNull);
}
- test_perform_notResolved() {
+ test_perform_strong_inferable() {
+ enableStrongMode();
+ Source source = newSource(
+ '/test.dart',
+ '''
+int a = b;
+int b = c;
+var d = 0;
+class A {}
+class C {
+ static final f = '';
+ var g = 0;
+}
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, RESOLVED_UNIT5,
+ matcher: isPartiallyResolveUnitReferencesTask);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ // INFERABLE_STATIC_VARIABLES_IN_UNIT
+ {
+ List<VariableElement> variables =
+ outputs[INFERABLE_STATIC_VARIABLES_IN_UNIT];
+ expect(variables, hasLength(4));
+ expect(variables.map((v) => v.displayName),
+ unorderedEquals(['a', 'b', 'd', 'f']));
+ }
+ // Test the state of the AST
+ TopLevelVariableDeclaration a = unit.declarations[0];
+ VariableDeclaration variableA = a.variables.variables[0];
+ SimpleIdentifier initializer = variableA.initializer;
+ expect(initializer.staticElement, isNotNull);
+ }
+
+ test_perform_strong_notResolved() {
enableStrongMode();
Source source = newSource(
'/test.dart',
@@ -2978,6 +3168,125 @@
}
@reflectiveTest
+class PropagateVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
+ void test_perform_cycle() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+final piFirst = true;
+final pi = piFirst ? 3.14 : tau / 2;
+final tau = piFirst ? pi * 2 : 6.28;
+''');
+ // compute
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ matcher: isPropagateVariableTypesInUnitTask);
+ CompilationUnit unit = outputs[RESOLVED_UNIT6];
+ // verify
+ TopLevelVariableElement piFirst =
+ AstFinder.getTopLevelVariableElement(unit, 'piFirst');
+ TopLevelVariableElement pi =
+ AstFinder.getTopLevelVariableElement(unit, 'pi');
+ TopLevelVariableElement tau =
+ AstFinder.getTopLevelVariableElement(unit, 'tau');
+ expect(piFirst.propagatedType, context.typeProvider.boolType);
+ expect(pi.propagatedType, isNull);
+ expect(tau.propagatedType, isNull);
+ }
+
+ void test_perform_topLevel() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+//final a = b + c.length;
+final a = b;
+final b = 1;
+final c = '2';
+''');
+ // compute
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+ matcher: isPropagateVariableTypesInUnitTask);
+ CompilationUnit unit = outputs[RESOLVED_UNIT6];
+ // verify
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+ expect(AstFinder.getTopLevelVariableElement(unit, 'a').propagatedType,
+ intType);
+ expect(AstFinder.getTopLevelVariableElement(unit, 'b').propagatedType,
+ intType);
+ expect(AstFinder.getTopLevelVariableElement(unit, 'c').propagatedType,
+ stringType);
+ }
+}
+
+@reflectiveTest
+class PropagateVariableTypeTaskTest extends _AbstractDartTaskTest {
+ void test_perform_cycle() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+final piFirst = true;
+final pi = piFirst ? 3.14 : tau / 2;
+final tau = piFirst ? pi * 2 : 6.28;
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement piFirst =
+ AstFinder.getTopLevelVariableElement(unit, 'piFirst');
+ TopLevelVariableElement pi =
+ AstFinder.getTopLevelVariableElement(unit, 'pi');
+ TopLevelVariableElement tau =
+ AstFinder.getTopLevelVariableElement(unit, 'tau');
+ // compute
+ computeResult(piFirst, PROPAGATED_VARIABLE,
+ matcher: isPropagateVariableTypeTask);
+ expect(piFirst.propagatedType, context.typeProvider.boolType);
+ expect(pi.propagatedType, isNull);
+ expect(tau.propagatedType, isNull);
+ }
+
+ void test_perform_null() {
+ enableStrongMode();
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+var a = null;
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement a = AstFinder.getTopLevelVariableElement(unit, 'a');
+ // compute
+ computeResult(a, PROPAGATED_VARIABLE, matcher: isPropagateVariableTypeTask);
+ expect(a.propagatedType, isNull);
+ }
+
+ void test_perform_topLevel() {
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+final a = b + c.length;
+final b = 1;
+final c = '2';
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+ CompilationUnit unit = outputs[RESOLVED_UNIT5];
+ TopLevelVariableElement elementA =
+ AstFinder.getTopLevelVariableElement(unit, 'a');
+ TopLevelVariableElement elementB =
+ AstFinder.getTopLevelVariableElement(unit, 'b');
+ TopLevelVariableElement elementC =
+ AstFinder.getTopLevelVariableElement(unit, 'c');
+ // compute
+ computeResult(elementA, PROPAGATED_VARIABLE,
+ matcher: isPropagateVariableTypeTask);
+ InterfaceType intType = context.typeProvider.intType;
+ InterfaceType stringType = context.typeProvider.stringType;
+ expect(elementA.propagatedType, intType);
+ expect(elementB.propagatedType, intType);
+ expect(elementC.propagatedType, stringType);
+ }
+}
+
+@reflectiveTest
class ResolveInstanceFieldsInUnitTaskTest extends _AbstractDartTaskTest {
@override
void setUp() {
@@ -3012,34 +3321,34 @@
DartType dynamicType = context.typeProvider.dynamicType;
computeResult(
- new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
// B.b2 shoud be resolved on the rhs, but not yet inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
computeResult(
- new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
- CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
// B.b2 should now be fully resolved and inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
// A.a2 should now be resolved on the rhs, but not yet inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
computeResult(
- new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
// A.a2 should now be fully resolved and inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
}
// Test inference of instance fields across units
@@ -3069,19 +3378,19 @@
DartType dynamicType = context.typeProvider.dynamicType;
computeResult(
- new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
- CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
// A.a2 should now be resolved on the rhs, but not yet inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
computeResult(
- new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
// A.a2 should now be fully resolved and inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
}
// Test inference of instance fields across units with cycles
@@ -3115,40 +3424,40 @@
DartType dynamicType = context.typeProvider.dynamicType;
computeResult(
- new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b1"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), dynamicType, intType);
computeResult(
- new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
- CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a1"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b1"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
computeResult(
- new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT7);
+ new LibrarySpecificUnit(sources[2], sources[2]), RESOLVED_UNIT8);
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a1"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b1"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
}
// Test inference between static and instance fields
@@ -3177,27 +3486,27 @@
DartType dynamicType = context.typeProvider.dynamicType;
computeResult(
- new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT7);
- CompilationUnit unit0 = outputs[RESOLVED_UNIT7];
+ new LibrarySpecificUnit(sources[0], sources[0]), RESOLVED_UNIT8);
+ CompilationUnit unit0 = outputs[RESOLVED_UNIT8];
// A.a2 should now be resolved on the rhs, but not yet inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
// B.b2 shoud be resolved on the rhs, but not yet inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "B", "b2"), dynamicType, intType);
+ AstFinder.getFieldInClass(unit0, "B", "b2"), dynamicType, intType);
computeResult(
- new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT7);
+ new LibrarySpecificUnit(sources[1], sources[1]), RESOLVED_UNIT8);
// A.a2 should now be fully resolved and inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), dynamicType, dynamicType);
// B.b2 should now be fully resolved and inferred.
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "B", "b2"), intType, intType);
}
}
@@ -3278,9 +3587,9 @@
}
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9,
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10,
matcher: isResolveUnitTask);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
FunctionDeclaration f = unit.declarations[0];
_assertResolved(f.functionExpression.body);
@@ -3291,6 +3600,33 @@
expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0));
}
+ void test_perform_ensurePropagatedVariableTypes() {
+ newSource(
+ '/lib.dart',
+ '''
+class A {
+ final v = 1;
+}
+''');
+ AnalysisTarget source = newSource(
+ '/test.dart',
+ '''
+import 'lib.dart';
+main(A a) {
+ a.v.isEven;
+}
+''');
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10,
+ matcher: isResolveUnitTask);
+ expect(outputs[RESOLVE_UNIT_ERRORS], hasLength(0));
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
+ FunctionDeclaration main = unit.declarations[0];
+ BlockFunctionBody body = main.functionExpression.body;
+ ExpressionStatement statement = body.block.statements.single;
+ Expression expression = statement.expression;
+ expect(expression.bestType, context.typeProvider.boolType);
+ }
+
void _assertResolved(FunctionBody body) {
ResolutionVerifier verifier = new ResolutionVerifier();
body.accept(verifier);
@@ -3534,14 +3870,17 @@
var pi = piFirst ? 3.14 : tau / 2;
var tau = piFirst ? pi * 2 : 6.28;
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
VariableElement piFirst =
- getTopLevelVariable(unit, 'piFirst').name.staticElement;
- VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
- VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
- Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
- as ConditionalExpression).condition;
+ AstFinder.getTopLevelVariable(unit, 'piFirst').name.staticElement;
+ VariableElement pi =
+ AstFinder.getTopLevelVariable(unit, 'pi').name.staticElement;
+ VariableElement tau =
+ AstFinder.getTopLevelVariable(unit, 'tau').name.staticElement;
+ Expression piFirstUse = (AstFinder
+ .getTopLevelVariable(unit, 'tau')
+ .initializer as ConditionalExpression).condition;
expect(piFirstUse.staticType, context.typeProvider.boolType);
expect(piFirst.type, context.typeProvider.boolType);
@@ -3573,26 +3912,26 @@
}
''');
computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT9];
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT10);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT10];
computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
- CompilationUnit unit2 = outputs[RESOLVED_UNIT9];
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT10);
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
assertVariableDeclarationTypes(
- getTopLevelVariable(unit1, "x"), intType, intType);
+ AstFinder.getTopLevelVariable(unit1, "x"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "A", "x"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit2, "y"), intType, intType);
+ AstFinder.getTopLevelVariable(unit2, "y"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit2, "B", "y"), intType, intType);
+ AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType);
List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
+ AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
assertAssignmentStatementTypes(statements[1], intType, intType);
assertAssignmentStatementTypes(statements[2], intType, intType);
@@ -3624,7 +3963,7 @@
'''
});
List<dynamic> units =
- computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+ computeLibraryResults(sources, RESOLVED_UNIT10).toList();
CompilationUnit unit0 = units[0];
CompilationUnit unit1 = units[1];
CompilationUnit unit2 = units[2];
@@ -3632,13 +3971,13 @@
InterfaceType intType = context.typeProvider.intType;
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
+ AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
assertAssignmentStatementTypes(statements[1], intType, intType);
}
@@ -3671,7 +4010,7 @@
'''
});
List<dynamic> units =
- computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+ computeLibraryResults(sources, RESOLVED_UNIT10).toList();
CompilationUnit unit0 = units[0];
CompilationUnit unit2 = units[2];
@@ -3679,9 +4018,13 @@
InterfaceType stringType = context.typeProvider.stringType;
assertVariableDeclarationStatementTypes(
- getStatementsInTopLevelFunction(unit0, "foo")[0], stringType, intType);
+ AstFinder.getStatementsInTopLevelFunction(unit0, "foo")[0],
+ stringType,
+ intType);
assertVariableDeclarationStatementTypes(
- getStatementsInTopLevelFunction(unit2, "foo")[0], stringType, intType);
+ AstFinder.getStatementsInTopLevelFunction(unit2, "foo")[0],
+ stringType,
+ intType);
}
// Test inference interactions between local variables and top level
@@ -3708,27 +4051,27 @@
}
''');
computeResult(
- new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT9);
- CompilationUnit unit1 = outputs[RESOLVED_UNIT9];
+ new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT10);
+ CompilationUnit unit1 = outputs[RESOLVED_UNIT10];
computeResult(
- new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT9);
- CompilationUnit unit2 = outputs[RESOLVED_UNIT9];
+ new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT10);
+ CompilationUnit unit2 = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
assertVariableDeclarationTypes(
- getTopLevelVariable(unit1, "x"), intType, intType);
+ AstFinder.getTopLevelVariable(unit1, "x"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "A", "x"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "A", "x"), intType, intType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit2, "y"), intType, intType);
+ AstFinder.getTopLevelVariable(unit2, "y"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit2, "B", "y"), intType, intType);
+ AstFinder.getFieldInClass(unit2, "B", "y"), intType, intType);
List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
+ AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
assertAssignmentStatementTypes(statements[0], intType, stringType);
assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3762,7 +4105,7 @@
'''
});
List<dynamic> units =
- computeLibraryResults(sources, RESOLVED_UNIT9).toList();
+ computeLibraryResults(sources, RESOLVED_UNIT10).toList();
CompilationUnit unit0 = units[0];
CompilationUnit unit1 = units[1];
CompilationUnit unit2 = units[2];
@@ -3770,17 +4113,17 @@
InterfaceType intType = context.typeProvider.intType;
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a1"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit0, "A", "a2"), intType, intType);
+ AstFinder.getFieldInClass(unit0, "A", "a2"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b1"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b1"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit1, "B", "b2"), intType, intType);
+ AstFinder.getFieldInClass(unit1, "B", "b2"), intType, intType);
List<Statement> statements =
- getStatementsInTopLevelFunction(unit2, "test1");
+ AstFinder.getStatementsInTopLevelFunction(unit2, "test1");
assertAssignmentStatementTypes(statements[1], intType, intType);
assertAssignmentStatementTypes(statements[2], intType, intType);
@@ -3798,13 +4141,14 @@
y = "hi";
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test");
assertVariableDeclarationStatementTypes(statements[0], intType, intType);
assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3836,13 +4180,14 @@
final z = 42; // should infer `int`
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
- List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
+ List<Statement> statements =
+ AstFinder.getStatementsInMethod(unit, "A", "test1");
assertVariableDeclarationStatementTypes(statements[0], intType, intType);
assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3857,9 +4202,9 @@
assertAssignmentStatementTypes(statements[8], intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x"), intType, intType);
+ AstFinder.getFieldInClass(unit, "A", "x"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "z"), intType, intType);
+ AstFinder.getFieldInClass(unit, "A", "z"), intType, intType);
}
// Test inference of instance fields across units
@@ -3884,13 +4229,14 @@
int y = 0; // field def after use
final z = 42; // should infer `int`
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test1");
assertVariableDeclarationStatementTypes(statements[0], intType, intType);
assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3905,11 +4251,11 @@
assertAssignmentStatementTypes(statements[8], intType, intType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "x"), intType, intType);
+ AstFinder.getTopLevelVariable(unit, "x"), intType, intType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "y"), intType, intType);
+ AstFinder.getTopLevelVariable(unit, "y"), intType, intType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "z"), intType, intType);
+ AstFinder.getTopLevelVariable(unit, "z"), intType, intType);
}
// Test inference between static and instance fields
@@ -3936,8 +4282,8 @@
new A().y2 = /*severe:StaticTypeError*/"hi";
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
@@ -3945,19 +4291,20 @@
DartType dynamicType = context.typeProvider.dynamicType;
assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "x"), dynamicType, bottomType);
+ AstFinder.getTopLevelVariable(unit, "x"), dynamicType, bottomType);
assertVariableDeclarationTypes(
- getTopLevelVariable(unit, "y"), intType, intType);
+ AstFinder.getTopLevelVariable(unit, "y"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
+ AstFinder.getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "y"), intType, intType);
+ AstFinder.getFieldInClass(unit, "A", "y"), intType, intType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
+ AstFinder.getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
assertVariableDeclarationTypes(
- getFieldInClass(unit, "A", "y2"), intType, intType);
+ AstFinder.getFieldInClass(unit, "A", "y2"), intType, intType);
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test");
assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
assertAssignmentStatementTypes(statements[1], intType, stringType);
@@ -3977,13 +4324,14 @@
x = "hi";
}
''');
- computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT9);
- CompilationUnit unit = outputs[RESOLVED_UNIT9];
+ computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT10);
+ CompilationUnit unit = outputs[RESOLVED_UNIT10];
InterfaceType intType = context.typeProvider.intType;
InterfaceType stringType = context.typeProvider.stringType;
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "test");
VariableDeclaration decl =
(statements[0] as VariableDeclarationStatement).variables.variables[0];
expect(decl.element.type, intType);
@@ -4021,7 +4369,8 @@
_fillErrorListener(STRONG_MODE_ERRORS);
expect(errorListener.errors, isEmpty);
- List<Statement> statements = getStatementsInTopLevelFunction(unit, "main");
+ List<Statement> statements =
+ AstFinder.getStatementsInTopLevelFunction(unit, "main");
ExpressionStatement statement = statements[1];
IndexExpression idx = statement.expression;
expect(DynamicInvoke.get(idx.target), isNotNull);
@@ -4045,7 +4394,7 @@
var errors = errorListener.errors;
expect(errors.length, 1);
- expect(errors[0].errorCode.name, "dev_compiler.StaticTypeError");
+ expect(errors[0].errorCode.name, "STRONG_MODE_STATIC_TYPE_ERROR");
}
}
@@ -4068,6 +4417,27 @@
]);
}
+ test_perform_ConstantValidator_duplicateFields() {
+ Source source = newSource(
+ '/test.dart',
+ '''
+class Test {
+ final int x = 1;
+ final int x = 2;
+ const Test();
+}
+
+main() {
+ const Test();
+}
+''');
+ LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+ computeResult(target, VERIFY_ERRORS, matcher: isVerifyUnitTask);
+ // validate
+ _fillErrorListener(VERIFY_ERRORS);
+ errorListener.assertNoErrors();
+ }
+
test_perform_directiveError() {
Source source = newSource(
'/test.dart',
@@ -4214,114 +4584,6 @@
context.analysisOptions = options;
}
- /**
- * Return the declaration of the class with the given [className] in the given
- * compilation [unit].
- */
- ClassDeclaration getClass(CompilationUnit unit, String className) {
- NodeList<CompilationUnitMember> unitMembers = unit.declarations;
- for (CompilationUnitMember unitMember in unitMembers) {
- if (unitMember is ClassDeclaration && unitMember.name.name == className) {
- return unitMember;
- }
- }
- fail('No class named $className in ${unit.element.source}');
- return null;
- }
-
- /**
- * Return the declaration of the field with the given [fieldName] in the class
- * with the given [className] in the given compilation [unit].
- */
- VariableDeclaration getFieldInClass(
- CompilationUnit unit, String className, String fieldName) {
- ClassDeclaration unitMember = getClass(unit, className);
- NodeList<ClassMember> classMembers = unitMember.members;
- for (ClassMember classMember in classMembers) {
- if (classMember is FieldDeclaration) {
- NodeList<VariableDeclaration> fields = classMember.fields.variables;
- for (VariableDeclaration field in fields) {
- if (field.name.name == fieldName) {
- return field;
- }
- }
- }
- }
- fail('No field named $fieldName in $className');
- return null;
- }
-
- /**
- * Return the declaration of the method with the given [methodName] in the
- * class with the given [className] in the given compilation [unit].
- */
- MethodDeclaration getMethodInClass(
- CompilationUnit unit, String className, String methodName) {
- ClassDeclaration unitMember = getClass(unit, className);
- NodeList<ClassMember> classMembers = unitMember.members;
- for (ClassMember classMember in classMembers) {
- if (classMember is MethodDeclaration) {
- if (classMember.name.name == methodName) {
- return classMember;
- }
- }
- }
- fail('No method named $methodName in $className');
- return null;
- }
-
- List<Statement> getStatementsInMethod(
- CompilationUnit unit, String className, String methodName) {
- MethodDeclaration method = getMethodInClass(unit, className, methodName);
- BlockFunctionBody body = method.body;
- return body.block.statements;
- }
-
- List<Statement> getStatementsInTopLevelFunction(
- CompilationUnit unit, String functionName) {
- FunctionDeclaration function = getTopLevelFunction(unit, functionName);
- BlockFunctionBody body = function.functionExpression.body;
- return body.block.statements;
- }
-
- /**
- * Return the declaration of the top-level function with the given
- * [functionName] in the given compilation [unit].
- */
- FunctionDeclaration getTopLevelFunction(
- CompilationUnit unit, String functionName) {
- NodeList<CompilationUnitMember> unitMembers = unit.declarations;
- for (CompilationUnitMember unitMember in unitMembers) {
- if (unitMember is FunctionDeclaration) {
- if (unitMember.name.name == functionName) {
- return unitMember;
- }
- }
- }
- return null;
- }
-
- /**
- * Return the declaration of the top-level variable with the given
- * [variableName] in the given compilation [unit].
- */
- VariableDeclaration getTopLevelVariable(
- CompilationUnit unit, String variableName) {
- NodeList<CompilationUnitMember> unitMembers = unit.declarations;
- for (CompilationUnitMember unitMember in unitMembers) {
- if (unitMember is TopLevelVariableDeclaration) {
- NodeList<VariableDeclaration> variables =
- unitMember.variables.variables;
- for (VariableDeclaration variable in variables) {
- if (variable.name.name == variableName) {
- return variable;
- }
- }
- }
- }
- return null;
- }
-
void setUp() {
super.setUp();
emptySource = newSource('/test.dart');
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 75c0a5a..eacff89 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -284,6 +284,16 @@
[AnalysisOptionsWarningCode.UNSUPPORTED_VALUE]);
}
+ test_analyzer_strong_mode_error_code_supported() {
+ validate(
+ '''
+analyzer:
+ errors:
+ strong_mode_assignment_cast: ignore
+''',
+ []);
+ }
+
test_analyzer_supported_exclude() {
validate(
'''
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 6e8ba4b..a1170ef 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -32,10 +32,15 @@
// it requires inference to work because of dartbug.com/23381
SplayTreeMap([int compare(K key1, K key2),
bool isValidKey(potentialKey)]) {
- : _comparator = /*warning:DownCastComposite*/(compare == null) ? Comparable.compare : compare,
- _validKey = /*info:InferredType should be pass*/(isValidKey != null) ? isValidKey : ((v) => true);
- _Predicate<Object> _v = /*warning:DownCastComposite*/(isValidKey != null) ? isValidKey : ((v) => true);
- _v = /*info:InferredType should be pass*/(isValidKey != null) ? _v : ((v) => true);
+ : _comparator = /*warning:DOWN_CAST_COMPOSITE*/(compare == null)
+ ? Comparable.compare : compare,
+ _validKey = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+ ? isValidKey : ((v) => true);
+ _Predicate<Object> _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+ ? isValidKey : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
+ // TODO(leafp): Fix unimplemented LUB in analyzer
+ _v = /*warning:DOWN_CAST_COMPOSITE*/(isValidKey != null)
+ ? _v : (/*info:INFERRED_TYPE_CLOSURE*/(v) => true);
}
}
void main() {
@@ -44,9 +49,9 @@
int i = 42;
// Check the boolean conversion of the condition.
- print((/*severe:StaticTypeError*/i) ? false : true);
- print((/*info:DownCastImplicit*/obj) ? false : true);
- print((/*info:DynamicCast*/dyn) ? false : true);
+ print((/*severe:STATIC_TYPE_ERROR*/i) ? false : true);
+ print((/*info:DOWN_CAST_IMPLICIT*/obj) ? false : true);
+ print((/*info:DYNAMIC_CAST*/dyn) ? false : true);
}
'''
});
@@ -60,24 +65,24 @@
bool b = false;
if (b) {}
- if (/*info:DynamicCast*/dyn) {}
- if (/*info:DownCastImplicit*/obj) {}
- if (/*severe:StaticTypeError*/i) {}
+ if (/*info:DYNAMIC_CAST*/dyn) {}
+ if (/*info:DOWN_CAST_IMPLICIT*/obj) {}
+ if (/*severe:STATIC_TYPE_ERROR*/i) {}
while (b) {}
- while (/*info:DynamicCast*/dyn) {}
- while (/*info:DownCastImplicit*/obj) {}
- while (/*severe:StaticTypeError*/i) {}
+ while (/*info:DYNAMIC_CAST*/dyn) {}
+ while (/*info:DOWN_CAST_IMPLICIT*/obj) {}
+ while (/*severe:STATIC_TYPE_ERROR*/i) {}
do {} while (b);
- do {} while (/*info:DynamicCast*/dyn);
- do {} while (/*info:DownCastImplicit*/obj);
- do {} while (/*severe:StaticTypeError*/i);
+ do {} while (/*info:DYNAMIC_CAST*/dyn);
+ do {} while (/*info:DOWN_CAST_IMPLICIT*/obj);
+ do {} while (/*severe:STATIC_TYPE_ERROR*/i);
for (;b;) {}
- for (;/*info:DynamicCast*/dyn;) {}
- for (;/*info:DownCastImplicit*/obj;) {}
- for (;/*severe:StaticTypeError*/i;) {}
+ for (;/*info:DYNAMIC_CAST*/dyn;) {}
+ for (;/*info:DOWN_CAST_IMPLICIT*/obj;) {}
+ for (;/*severe:STATIC_TYPE_ERROR*/i;) {}
}
'''
});
@@ -99,43 +104,43 @@
double y;
// The analyzer has what I believe is a bug (dartbug.com/23252) which
// causes the return type of calls to f to be treated as dynamic.
- x = /*info:DynamicCast should be pass*/f(3);
- x = /*severe:StaticTypeError*/f.col(3.0);
- y = /*info:DynamicCast should be severe:StaticTypeError*/f(3);
+ x = /*info:DYNAMIC_CAST should be pass*/f(3);
+ x = /*severe:STATIC_TYPE_ERROR*/f.col(3.0);
+ y = /*info:DYNAMIC_CAST should be severe:STATIC_TYPE_ERROR*/f(3);
y = f.col(3.0);
- f(/*severe:StaticTypeError*/3.0);
- f.col(/*severe:StaticTypeError*/3);
+ f(/*severe:STATIC_TYPE_ERROR*/3.0);
+ f.col(/*severe:STATIC_TYPE_ERROR*/3);
}
{
Function f = new B();
int x;
double y;
- x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
- x = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
- y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
- y = /*info:DynamicCast, info:DynamicInvoke*/f.col(3.0);
- (/*info:DynamicInvoke*/f(3.0));
- (/*info:DynamicInvoke*/f.col(3));
+ x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+ x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
+ y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+ y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f.col(3.0);
+ (/*info:DYNAMIC_INVOKE*/f(3.0));
+ (/*info:DYNAMIC_INVOKE*/f.col(3));
}
{
A f = new B();
int x;
double y;
- x = /*info:DynamicCast, info:DynamicInvoke*/f(3);
- y = /*info:DynamicCast, info:DynamicInvoke*/f(3);
- (/*info:DynamicInvoke*/f(3.0));
+ x = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+ y = /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/f(3);
+ (/*info:DYNAMIC_INVOKE*/f(3.0));
}
{
dynamic g = new B();
- (/*info:DynamicInvoke*/g.call(32.0));
- (/*info:DynamicInvoke*/g.col(42.0));
- (/*info:DynamicInvoke*/g.foo(42.0));
- (/*info:DynamicInvoke*/g.x);
+ (/*info:DYNAMIC_INVOKE*/g.call(32.0));
+ (/*info:DYNAMIC_INVOKE*/g.col(42.0));
+ (/*info:DYNAMIC_INVOKE*/g.foo(42.0));
+ (/*info:DYNAMIC_INVOKE*/g.x);
A f = new B();
f.call(32.0);
- (/*info:DynamicInvoke*/f.col(42.0));
- (/*info:DynamicInvoke*/f.foo(42.0));
- (/*info:DynamicInvoke*/f.x);
+ (/*info:DYNAMIC_INVOKE*/f.col(42.0));
+ (/*info:DYNAMIC_INVOKE*/f.foo(42.0));
+ (/*info:DYNAMIC_INVOKE*/f.x);
}
}
'''
@@ -152,8 +157,8 @@
class A {
String x = "hello world";
- void baz1(y) => x + /*info:DynamicCast*/y;
- static baz2(y) => /*info:DynamicInvoke*/y + y;
+ void baz1(y) => x + /*info:DYNAMIC_CAST*/y;
+ static baz2(y) => /*info:DYNAMIC_INVOKE*/y + y;
}
void foo(String str) {
@@ -165,7 +170,7 @@
}
void bar(a) {
- foo(/*info:DynamicCast,info:DynamicInvoke*/a.x);
+ foo(/*info:DYNAMIC_CAST,info:DYNAMIC_INVOKE*/a.x);
}
baz() => new B();
@@ -178,42 +183,42 @@
void main() {
var a = new A();
bar(a);
- (/*info:DynamicInvoke*/bar1(a));
+ (/*info:DYNAMIC_INVOKE*/bar1(a));
var b = bar;
- (/*info:DynamicInvoke*/b(a));
+ (/*info:DYNAMIC_INVOKE*/b(a));
var f1 = foo;
f1("hello");
dynamic f2 = foo;
- (/*info:DynamicInvoke*/f2("hello"));
+ (/*info:DYNAMIC_INVOKE*/f2("hello"));
DynFun f3 = foo;
- (/*info:DynamicInvoke*/f3("hello"));
- (/*info:DynamicInvoke*/f3(42));
+ (/*info:DYNAMIC_INVOKE*/f3("hello"));
+ (/*info:DYNAMIC_INVOKE*/f3(42));
StrFun f4 = foo;
f4("hello");
a.baz1("hello");
var b1 = a.baz1;
- (/*info:DynamicInvoke*/b1("hello"));
+ (/*info:DYNAMIC_INVOKE*/b1("hello"));
A.baz2("hello");
var b2 = A.baz2;
- (/*info:DynamicInvoke*/b2("hello"));
+ (/*info:DYNAMIC_INVOKE*/b2("hello"));
dynamic a1 = new B();
- (/*info:DynamicInvoke*/a1.x);
+ (/*info:DYNAMIC_INVOKE*/a1.x);
a1.toString();
- (/*info:DynamicInvoke*/a1.toString(42));
+ (/*info:DYNAMIC_INVOKE*/a1.toString(42));
var toStringClosure = a1.toString;
- (/*info:DynamicInvoke*/a1.toStringClosure());
- (/*info:DynamicInvoke*/a1.toStringClosure(42));
- (/*info:DynamicInvoke*/a1.toStringClosure("hello"));
+ (/*info:DYNAMIC_INVOKE*/a1.toStringClosure());
+ (/*info:DYNAMIC_INVOKE*/a1.toStringClosure(42));
+ (/*info:DYNAMIC_INVOKE*/a1.toStringClosure("hello"));
a1.hashCode;
dynamic toString = () => null;
- (/*info:DynamicInvoke*/toString());
+ (/*info:DYNAMIC_INVOKE*/toString());
- (/*info:DynamicInvoke*/helper.toString());
+ (/*info:DYNAMIC_INVOKE*/helper.toString());
var toStringClosure2 = helper.toString;
- (/*info:DynamicInvoke*/toStringClosure2());
- int hashCode = /*info:DynamicCast*/helper.hashCode;
+ (/*info:DYNAMIC_INVOKE*/toStringClosure2());
+ int hashCode = /*info:DYNAMIC_CAST*/helper.hashCode;
baz().toString();
baz().hashCode;
@@ -230,27 +235,27 @@
int x;
String y;
- A(this.x) : this.y = /*severe:StaticTypeError*/42;
+ A(this.x) : this.y = /*severe:STATIC_TYPE_ERROR*/42;
- A.c1(p): this.x = /*info:DownCastImplicit*/z, this.y = /*info:DynamicCast*/p;
+ A.c1(p): this.x = /*info:DOWN_CAST_IMPLICIT*/z, this.y = /*info:DYNAMIC_CAST*/p;
A.c2(this.x, this.y);
- A.c3(/*severe:InvalidParameterDeclaration*/num this.x, String this.y);
+ A.c3(/*severe:INVALID_PARAMETER_DECLARATION*/num this.x, String this.y);
}
class B extends A {
- B() : super(/*severe:StaticTypeError*/"hello");
+ B() : super(/*severe:STATIC_TYPE_ERROR*/"hello");
- B.c2(int x, String y) : super.c2(/*severe:StaticTypeError*/y,
- /*severe:StaticTypeError*/x);
+ B.c2(int x, String y) : super.c2(/*severe:STATIC_TYPE_ERROR*/y,
+ /*severe:STATIC_TYPE_ERROR*/x);
- B.c3(num x, Object y) : super.c3(x, /*info:DownCastImplicit*/y);
+ B.c3(num x, Object y) : super.c3(x, /*info:DOWN_CAST_IMPLICIT*/y);
}
void main() {
- A a = new A.c2(/*info:DownCastImplicit*/z, /*severe:StaticTypeError*/z);
- var b = new B.c2(/*severe:StaticTypeError*/"hello", /*info:DownCastImplicit*/obj);
+ A a = new A.c2(/*info:DOWN_CAST_IMPLICIT*/z, /*severe:STATIC_TYPE_ERROR*/z);
+ var b = new B.c2(/*severe:STATIC_TYPE_ERROR*/"hello", /*info:DOWN_CAST_IMPLICIT*/obj);
}
'''
});
@@ -258,7 +263,7 @@
testChecker('Unbound variable', {
'/main.dart': '''
void main() {
- dynamic y = /*pass should be severe:StaticTypeError*/unboundVariable;
+ dynamic y = /*pass should be severe:STATIC_TYPE_ERROR*/unboundVariable;
}
'''
});
@@ -266,7 +271,18 @@
testChecker('Unbound type name', {
'/main.dart': '''
void main() {
- /*pass should be severe:StaticTypeError*/AToB y;
+ /*pass should be severe:STATIC_TYPE_ERROR*/AToB y;
+ }
+ '''
+ });
+
+ // 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:STATIC_TYPE_ERROR*/foo();
}
'''
});
@@ -310,11 +326,11 @@
A a;
B b;
o = y;
- i = /*info:DynamicCast*/y;
- d = /*info:DynamicCast*/y;
- n = /*info:DynamicCast*/y;
- a = /*info:DynamicCast*/y;
- b = /*info:DynamicCast*/y;
+ i = /*info:DYNAMIC_CAST*/y;
+ d = /*info:DYNAMIC_CAST*/y;
+ n = /*info:DYNAMIC_CAST*/y;
+ a = /*info:DYNAMIC_CAST*/y;
+ b = /*info:DYNAMIC_CAST*/y;
}
'''
});
@@ -335,11 +351,11 @@
B b;
y = a;
o = a;
- i = /*severe:StaticTypeError*/a;
- d = /*severe:StaticTypeError*/a;
- n = /*severe:StaticTypeError*/a;
+ i = /*severe:STATIC_TYPE_ERROR*/a;
+ d = /*severe:STATIC_TYPE_ERROR*/a;
+ n = /*severe:STATIC_TYPE_ERROR*/a;
a = a;
- b = /*info:DownCastImplicit*/a;
+ b = /*info:DOWN_CAST_IMPLICIT*/a;
}
'''
});
@@ -362,12 +378,12 @@
C c;
y = b;
o = b;
- i = /*severe:StaticTypeError*/b;
- d = /*severe:StaticTypeError*/b;
- n = /*severe:StaticTypeError*/b;
+ i = /*severe:STATIC_TYPE_ERROR*/b;
+ d = /*severe:STATIC_TYPE_ERROR*/b;
+ n = /*severe:STATIC_TYPE_ERROR*/b;
a = b;
b = b;
- c = /*severe:StaticTypeError*/b;
+ c = /*severe:STATIC_TYPE_ERROR*/b;
}
'''
});
@@ -392,21 +408,21 @@
top = bot;
}
{
- left = /*info:DownCastImplicit*/top;
+ left = /*info:DOWN_CAST_IMPLICIT*/top;
left = left;
- left = /*severe:StaticTypeError*/right;
+ left = /*severe:STATIC_TYPE_ERROR*/right;
left = bot;
}
{
- right = /*info:DownCastImplicit*/top;
- right = /*severe:StaticTypeError*/left;
+ right = /*info:DOWN_CAST_IMPLICIT*/top;
+ right = /*severe:STATIC_TYPE_ERROR*/left;
right = right;
right = bot;
}
{
- bot = /*info:DownCastImplicit*/top;
- bot = /*info:DownCastImplicit*/left;
- bot = /*info:DownCastImplicit*/right;
+ bot = /*info:DOWN_CAST_IMPLICIT*/top;
+ bot = /*info:DOWN_CAST_IMPLICIT*/left;
+ bot = /*info:DOWN_CAST_IMPLICIT*/right;
bot = bot;
}
}
@@ -425,7 +441,7 @@
Object top(int x) => x;
int left(int x) => x;
Object right(Object x) => x;
- int _bot(Object x) => /*info:DownCastImplicit*/x;
+ int _bot(Object x) => /*info:DOWN_CAST_IMPLICIT*/x;
int bot(Object x) => x as int;
void main() {
@@ -442,23 +458,23 @@
}
{
Left f;
- f = /*warning:DownCastComposite*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
f = bot;
}
{
Right f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
f = right;
f = bot;
}
{
Bot f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
- f = /*warning:DownCastComposite*/right;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/right;
f = bot;
}
}
@@ -478,7 +494,7 @@
typedef B Bot(A x); // Bottom of the lattice
B left(B x) => x;
- B _bot(A x) => /*info:DownCastImplicit*/x;
+ B _bot(A x) => /*info:DOWN_CAST_IMPLICIT*/x;
B bot(A x) => x as B;
A top(B x) => x;
A right(A x) => x;
@@ -497,23 +513,23 @@
}
{
Left f;
- f = /*warning:DownCastComposite*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
f = bot;
}
{
Right f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
f = right;
f = bot;
}
{
Bot f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
- f = /*warning:DownCastComposite*/right;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/right;
f = bot;
}
}
@@ -533,7 +549,7 @@
dynamic left(A x) => x;
A bot(A x) => x;
dynamic top(dynamic x) => x;
- A right(dynamic x) => /*info:DynamicCast*/x;
+ A right(dynamic x) => /*info:DYNAMIC_CAST*/x;
void main() {
{
@@ -545,23 +561,23 @@
}
{
Left f;
- f = /*warning:DownCastComposite*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DownCastComposite*/right;
+ f = /*warning:DOWN_CAST_COMPOSITE*/right;
f = bot;
}
{
Right f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
f = right;
f = bot;
}
{
Bottom f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
- f = /*warning:DownCastComposite*/right;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/right;
f = bot;
}
}
@@ -591,23 +607,23 @@
}
{
Function2<B, B> f;
- f = /*warning:DownCastComposite*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
f = bot;
}
{
Function2<A, A> f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
f = right;
f = bot;
}
{
Function2<A, B> f;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
- f = /*warning:DownCastComposite*/right;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/right;
f = bot;
}
}
@@ -634,19 +650,19 @@
top = top;
top = left;
- left = /*warning:DownCastComposite*/top;
+ left = /*warning:DOWN_CAST_COMPOSITE*/top;
left = left;
- left = /*warning:DownCastComposite*/right; // Should we reject this?
+ left = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
left = bot;
- right = /*warning:DownCastComposite*/top;
- right = /*warning:DownCastComposite*/left; // Should we reject this?
+ right = /*warning:DOWN_CAST_COMPOSITE*/top;
+ right = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
right = right;
right = bot;
- bot = /*warning:DownCastComposite*/top;
- bot = /*warning:DownCastComposite*/left;
- bot = /*warning:DownCastComposite*/right;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/top;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/left;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/right;
bot = bot;
}
}
@@ -667,20 +683,20 @@
BToA top(AToB f) => f;
AToB left(AToB f) => f;
BToA right(BToA f) => f;
- AToB _bot(BToA f) => /*warning:DownCastComposite*/f;
+ AToB _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
AToB bot(BToA f) => f as AToB;
Function2<B, A> top(AToB f) => f;
Function2<A, B> left(AToB f) => f;
Function2<B, A> right(BToA f) => f;
- Function2<A, B> _bot(BToA f) => /*warning:DownCastComposite*/f;
+ Function2<A, B> _bot(BToA f) => /*warning:DOWN_CAST_COMPOSITE*/f;
Function2<A, B> bot(BToA f) => f as Function2<A, B>;
BToA top(Function2<A, B> f) => f;
AToB left(Function2<A, B> f) => f;
BToA right(Function2<B, A> f) => f;
- AToB _bot(Function2<B, A> f) => /*warning:DownCastComposite*/f;
+ AToB _bot(Function2<B, A> f) => /*warning:DOWN_CAST_COMPOSITE*/f;
AToB bot(Function2<B, A> f) => f as AToB;
void main() {
@@ -693,24 +709,24 @@
}
{
Function2<AToB, AToB> f; // Left
- f = /*warning:DownCastComposite*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
f = left;
- f = /*warning:DownCastComposite*/right; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/right; // Should we reject this?
f = bot;
}
{
Function2<BToA, BToA> f; // Right
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left; // Should we reject this?
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left; // Should we reject this?
f = right;
f = bot;
}
{
Function2<BToA, AToB> f; // Bot
f = bot;
- f = /*warning:DownCastComposite*/left;
- f = /*warning:DownCastComposite*/top;
- f = /*warning:DownCastComposite*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
+ f = /*warning:DOWN_CAST_COMPOSITE*/top;
+ f = /*warning:DOWN_CAST_COMPOSITE*/left;
}
}
'''
@@ -737,21 +753,21 @@
top = top;
top = left;
- left = /*warning:DownCastComposite*/top;
+ left = /*warning:DOWN_CAST_COMPOSITE*/top;
left = left;
left =
- /*warning:DownCastComposite should be severe:StaticTypeError*/right;
+ /*warning:DOWN_CAST_COMPOSITE should be severe:STATIC_TYPE_ERROR*/right;
left = bot;
- right = /*warning:DownCastComposite*/top;
+ right = /*warning:DOWN_CAST_COMPOSITE*/top;
right =
- /*warning:DownCastComposite should be severe:StaticTypeError*/left;
+ /*warning:DOWN_CAST_COMPOSITE should be severe:STATIC_TYPE_ERROR*/left;
right = right;
right = bot;
- bot = /*warning:DownCastComposite*/top;
- bot = /*warning:DownCastComposite*/left;
- bot = /*warning:DownCastComposite*/right;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/top;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/left;
+ bot = /*warning:DOWN_CAST_COMPOSITE*/right;
bot = bot;
}
}
@@ -786,92 +802,92 @@
r = r;
r = o;
- r = /*severe:StaticTypeError*/n;
- r = /*severe:StaticTypeError*/rr;
+ r = /*severe:STATIC_TYPE_ERROR*/n;
+ r = /*severe:STATIC_TYPE_ERROR*/rr;
r = ro;
r = rn;
r = oo;
- r = /*severe:StaticTypeError*/nn;
- r = /*severe:StaticTypeError*/nnn;
+ r = /*severe:STATIC_TYPE_ERROR*/nn;
+ r = /*severe:STATIC_TYPE_ERROR*/nnn;
- o = /*warning:DownCastComposite*/r;
+ o = /*warning:DOWN_CAST_COMPOSITE*/r;
o = o;
- o = /*severe:StaticTypeError*/n;
- o = /*severe:StaticTypeError*/rr;
- o = /*severe:StaticTypeError*/ro;
- o = /*severe:StaticTypeError*/rn;
+ o = /*severe:STATIC_TYPE_ERROR*/n;
+ o = /*severe:STATIC_TYPE_ERROR*/rr;
+ o = /*severe:STATIC_TYPE_ERROR*/ro;
+ o = /*severe:STATIC_TYPE_ERROR*/rn;
o = oo;
- o = /*severe:StaticTypeError*/nn
- o = /*severe:StaticTypeError*/nnn;
+ o = /*severe:STATIC_TYPE_ERROR*/nn
+ o = /*severe:STATIC_TYPE_ERROR*/nnn;
- n = /*severe:StaticTypeError*/r;
- n = /*severe:StaticTypeError*/o;
+ n = /*severe:STATIC_TYPE_ERROR*/r;
+ n = /*severe:STATIC_TYPE_ERROR*/o;
n = n;
- n = /*severe:StaticTypeError*/rr;
- n = /*severe:StaticTypeError*/ro;
- n = /*severe:StaticTypeError*/rn;
- n = /*severe:StaticTypeError*/oo;
+ n = /*severe:STATIC_TYPE_ERROR*/rr;
+ n = /*severe:STATIC_TYPE_ERROR*/ro;
+ n = /*severe:STATIC_TYPE_ERROR*/rn;
+ n = /*severe:STATIC_TYPE_ERROR*/oo;
n = nn;
n = nnn;
- rr = /*severe:StaticTypeError*/r;
- rr = /*severe:StaticTypeError*/o;
- rr = /*severe:StaticTypeError*/n;
+ rr = /*severe:STATIC_TYPE_ERROR*/r;
+ rr = /*severe:STATIC_TYPE_ERROR*/o;
+ rr = /*severe:STATIC_TYPE_ERROR*/n;
rr = rr;
rr = ro;
- rr = /*severe:StaticTypeError*/rn;
+ rr = /*severe:STATIC_TYPE_ERROR*/rn;
rr = oo;
- rr = /*severe:StaticTypeError*/nn;
- rr = /*severe:StaticTypeError*/nnn;
+ rr = /*severe:STATIC_TYPE_ERROR*/nn;
+ rr = /*severe:STATIC_TYPE_ERROR*/nnn;
- ro = /*warning:DownCastComposite*/r;
- ro = /*severe:StaticTypeError*/o;
- ro = /*severe:StaticTypeError*/n;
- ro = /*warning:DownCastComposite*/rr;
+ ro = /*warning:DOWN_CAST_COMPOSITE*/r;
+ ro = /*severe:STATIC_TYPE_ERROR*/o;
+ ro = /*severe:STATIC_TYPE_ERROR*/n;
+ ro = /*warning:DOWN_CAST_COMPOSITE*/rr;
ro = ro;
- ro = /*severe:StaticTypeError*/rn;
+ ro = /*severe:STATIC_TYPE_ERROR*/rn;
ro = oo;
- ro = /*severe:StaticTypeError*/nn;
- ro = /*severe:StaticTypeError*/nnn;
+ ro = /*severe:STATIC_TYPE_ERROR*/nn;
+ ro = /*severe:STATIC_TYPE_ERROR*/nnn;
- rn = /*warning:DownCastComposite*/r;
- rn = /*severe:StaticTypeError*/o;
- rn = /*severe:StaticTypeError*/n;
- rn = /*severe:StaticTypeError*/rr;
- rn = /*severe:StaticTypeError*/ro;
+ rn = /*warning:DOWN_CAST_COMPOSITE*/r;
+ rn = /*severe:STATIC_TYPE_ERROR*/o;
+ rn = /*severe:STATIC_TYPE_ERROR*/n;
+ rn = /*severe:STATIC_TYPE_ERROR*/rr;
+ rn = /*severe:STATIC_TYPE_ERROR*/ro;
rn = rn;
- rn = /*severe:StaticTypeError*/oo;
- rn = /*severe:StaticTypeError*/nn;
- rn = /*severe:StaticTypeError*/nnn;
+ rn = /*severe:STATIC_TYPE_ERROR*/oo;
+ rn = /*severe:STATIC_TYPE_ERROR*/nn;
+ rn = /*severe:STATIC_TYPE_ERROR*/nnn;
- oo = /*warning:DownCastComposite*/r;
- oo = /*warning:DownCastComposite*/o;
- oo = /*severe:StaticTypeError*/n;
- oo = /*warning:DownCastComposite*/rr;
- oo = /*warning:DownCastComposite*/ro;
- oo = /*severe:StaticTypeError*/rn;
+ oo = /*warning:DOWN_CAST_COMPOSITE*/r;
+ oo = /*warning:DOWN_CAST_COMPOSITE*/o;
+ oo = /*severe:STATIC_TYPE_ERROR*/n;
+ oo = /*warning:DOWN_CAST_COMPOSITE*/rr;
+ oo = /*warning:DOWN_CAST_COMPOSITE*/ro;
+ oo = /*severe:STATIC_TYPE_ERROR*/rn;
oo = oo;
- oo = /*severe:StaticTypeError*/nn;
- oo = /*severe:StaticTypeError*/nnn;
+ oo = /*severe:STATIC_TYPE_ERROR*/nn;
+ oo = /*severe:STATIC_TYPE_ERROR*/nnn;
- nn = /*severe:StaticTypeError*/r;
- nn = /*severe:StaticTypeError*/o;
- nn = /*warning:DownCastComposite*/n;
- nn = /*severe:StaticTypeError*/rr;
- nn = /*severe:StaticTypeError*/ro;
- nn = /*severe:StaticTypeError*/rn;
- nn = /*severe:StaticTypeError*/oo;
+ nn = /*severe:STATIC_TYPE_ERROR*/r;
+ nn = /*severe:STATIC_TYPE_ERROR*/o;
+ nn = /*warning:DOWN_CAST_COMPOSITE*/n;
+ nn = /*severe:STATIC_TYPE_ERROR*/rr;
+ nn = /*severe:STATIC_TYPE_ERROR*/ro;
+ nn = /*severe:STATIC_TYPE_ERROR*/rn;
+ nn = /*severe:STATIC_TYPE_ERROR*/oo;
nn = nn;
nn = nnn;
- nnn = /*severe:StaticTypeError*/r;
- nnn = /*severe:StaticTypeError*/o;
- nnn = /*warning:DownCastComposite*/n;
- nnn = /*severe:StaticTypeError*/rr;
- nnn = /*severe:StaticTypeError*/ro;
- nnn = /*severe:StaticTypeError*/rn;
- nnn = /*severe:StaticTypeError*/oo;
- nnn = /*warning:DownCastComposite*/nn;
+ nnn = /*severe:STATIC_TYPE_ERROR*/r;
+ nnn = /*severe:STATIC_TYPE_ERROR*/o;
+ nnn = /*warning:DOWN_CAST_COMPOSITE*/n;
+ nnn = /*severe:STATIC_TYPE_ERROR*/rr;
+ nnn = /*severe:STATIC_TYPE_ERROR*/ro;
+ nnn = /*severe:STATIC_TYPE_ERROR*/rn;
+ nnn = /*severe:STATIC_TYPE_ERROR*/oo;
+ nnn = /*warning:DOWN_CAST_COMPOSITE*/nn;
nnn = nnn;
}
'''
@@ -894,38 +910,38 @@
{
I2I f;
f = new A();
- f = /*severe:StaticTypeError*/new B();
+ f = /*severe:STATIC_TYPE_ERROR*/new B();
f = i2i;
- f = /*warning:DownCastComposite*/n2n;
- f = /*warning:DownCastComposite*/i2i as Object;
- f = /*warning:DownCastComposite*/n2n as Function;
+ f = /*warning:DOWN_CAST_COMPOSITE*/n2n;
+ f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
+ f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
}
{
N2N f;
- f = /*severe:StaticTypeError*/new A();
+ f = /*severe:STATIC_TYPE_ERROR*/new A();
f = new B();
- f = /*warning:DownCastComposite*/i2i;
+ f = /*warning:DOWN_CAST_COMPOSITE*/i2i;
f = n2n;
- f = /*warning:DownCastComposite*/i2i as Object;
- f = /*warning:DownCastComposite*/n2n as Function;
+ f = /*warning:DOWN_CAST_COMPOSITE*/i2i as Object;
+ f = /*warning:DOWN_CAST_COMPOSITE*/n2n as Function;
}
{
A f;
f = new A();
- f = /*severe:StaticTypeError*/new B();
- f = /*severe:StaticTypeError*/i2i;
- f = /*severe:StaticTypeError*/n2n;
- f = /*info:DownCastImplicit*/i2i as Object;
- f = /*info:DownCastImplicit*/n2n as Function;
+ f = /*severe:STATIC_TYPE_ERROR*/new B();
+ f = /*severe:STATIC_TYPE_ERROR*/i2i;
+ f = /*severe:STATIC_TYPE_ERROR*/n2n;
+ f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
+ f = /*info:DOWN_CAST_IMPLICIT*/n2n as Function;
}
{
B f;
- f = /*severe:StaticTypeError*/new A();
+ f = /*severe:STATIC_TYPE_ERROR*/new A();
f = new B();
- f = /*severe:StaticTypeError*/i2i;
- f = /*severe:StaticTypeError*/n2n;
- f = /*info:DownCastImplicit*/i2i as Object;
- f = /*info:DownCastImplicit*/n2n as Function;
+ f = /*severe:STATIC_TYPE_ERROR*/i2i;
+ f = /*severe:STATIC_TYPE_ERROR*/n2n;
+ f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
+ f = /*info:DOWN_CAST_IMPLICIT*/n2n as Function;
}
{
Function f;
@@ -933,7 +949,7 @@
f = new B();
f = i2i;
f = n2n;
- f = /*info:DownCastImplicit*/i2i as Object;
+ f = /*info:DOWN_CAST_IMPLICIT*/i2i as Object;
f = (n2n as Function);
}
}
@@ -992,36 +1008,36 @@
lOfOs = lOfAs;
}
{
- lOfAs = /*warning:DownCastComposite*/mOfDs;
- lOfAs = /*severe:StaticTypeError*/mOfOs;
+ lOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
+ lOfAs = /*severe:STATIC_TYPE_ERROR*/mOfOs;
lOfAs = mOfAs;
- lOfAs = /*warning:DownCastComposite*/lOfDs;
- lOfAs = /*info:DownCastImplicit*/lOfOs;
+ lOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
+ lOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
lOfAs = lOfAs;
}
{
mOfDs = mOfDs;
mOfDs = mOfOs;
mOfDs = mOfAs;
- mOfDs = /*info:DownCastImplicit*/lOfDs;
- mOfDs = /*info:DownCastImplicit*/lOfOs;
- mOfDs = /*warning:DownCastComposite*/lOfAs;
+ mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
+ mOfDs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+ mOfDs = /*warning:DOWN_CAST_COMPOSITE*/lOfAs;
}
{
mOfOs = mOfDs;
mOfOs = mOfOs;
mOfOs = mOfAs;
- mOfOs = /*info:DownCastImplicit*/lOfDs;
- mOfOs = /*info:DownCastImplicit*/lOfOs;
- mOfOs = /*severe:StaticTypeError*/lOfAs;
+ mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfDs;
+ mOfOs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+ mOfOs = /*severe:STATIC_TYPE_ERROR*/lOfAs;
}
{
- mOfAs = /*warning:DownCastComposite*/mOfDs;
- mOfAs = /*info:DownCastImplicit*/mOfOs;
+ mOfAs = /*warning:DOWN_CAST_COMPOSITE*/mOfDs;
+ mOfAs = /*info:DOWN_CAST_IMPLICIT*/mOfOs;
mOfAs = mOfAs;
- mOfAs = /*warning:DownCastComposite*/lOfDs;
- mOfAs = /*info:DownCastImplicit*/lOfOs;
- mOfAs = /*info:DownCastImplicit*/lOfAs;
+ mOfAs = /*warning:DOWN_CAST_COMPOSITE*/lOfDs;
+ mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfOs;
+ mOfAs = /*info:DOWN_CAST_IMPLICIT*/lOfAs;
}
}
@@ -1036,9 +1052,9 @@
String s = "hello";
{
List<int> l = <int>[i];
- l = <int>[/*severe:StaticTypeError*/s];
- l = <int>[/*info:DownCastImplicit*/n];
- l = <int>[i, /*info:DownCastImplicit*/n, /*severe:StaticTypeError*/s];
+ l = <int>[/*severe:STATIC_TYPE_ERROR*/s];
+ l = <int>[/*info:DOWN_CAST_IMPLICIT*/n];
+ l = <int>[i, /*info:DOWN_CAST_IMPLICIT*/n, /*severe:STATIC_TYPE_ERROR*/s];
}
{
List l = [i];
@@ -1048,11 +1064,11 @@
}
{
Map<String, int> m = <String, int>{s: i};
- m = <String, int>{s: /*severe:StaticTypeError*/s};
- m = <String, int>{s: /*info:DownCastImplicit*/n};
+ m = <String, int>{s: /*severe:STATIC_TYPE_ERROR*/s};
+ m = <String, int>{s: /*info:DOWN_CAST_IMPLICIT*/n};
m = <String, int>{s: i,
- s: /*info:DownCastImplicit*/n,
- s: /*severe:StaticTypeError*/s};
+ s: /*info:DOWN_CAST_IMPLICIT*/n,
+ s: /*severe:STATIC_TYPE_ERROR*/s};
}
// TODO(leafp): We can't currently test for key errors since the
// error marker binds to the entire entry.
@@ -1075,15 +1091,15 @@
'/main.dart': '''
class A {
static const num n = 3.0;
- static const int i = /*info:AssignmentCast*/n;
+ static const int i = /*info:ASSIGNMENT_CAST*/n;
final int fi;
- const A(num a) : this.fi = /*info:DownCastImplicit*/a;
+ const A(num a) : this.fi = /*info:DOWN_CAST_IMPLICIT*/a;
}
class B extends A {
- const B(Object a) : super(/*info:DownCastImplicit*/a);
+ const B(Object a) : super(/*info:DOWN_CAST_IMPLICIT*/a);
}
void foo(Object o) {
- var a = const A(/*info:DownCastImplicit*/o);
+ var a = const A(/*info:DOWN_CAST_IMPLICIT*/o);
}
'''
});
@@ -1093,18 +1109,27 @@
main() {
bool b = true;
num x = b ? 1 : 2.3;
- int y = /*info:AssignmentCast*/b ? 1 : 2.3;
+ int y = /*info:ASSIGNMENT_CAST*/b ? 1 : 2.3;
String z = !b ? "hello" : null;
z = b ? null : "hello";
}
'''
});
+ // 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 {
A(A x) {}
- A.two() : this(/*severe:StaticTypeError*/3);
+ A.two() : this(/*severe:STATIC_TYPE_ERROR*/3);
}
'''
});
@@ -1113,7 +1138,7 @@
'/main.dart': '''
class A { A(A x) {} }
class B extends A {
- B() : super(/*severe:StaticTypeError*/3);
+ B() : super(/*severe:STATIC_TYPE_ERROR*/3);
}
'''
});
@@ -1132,17 +1157,17 @@
}
class Child extends Base {
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/A f1; // invalid for getter
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/C f2; // invalid for setter
- /*severe:InvalidFieldOverride*/var f3;
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
+ /*severe:INVALID_FIELD_OVERRIDE*/var f3;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic f4;
}
class Child2 implements Base {
- /*severe:InvalidMethodOverride*/A f1; // invalid for getter
- /*severe:InvalidMethodOverride*/C f2; // invalid for setter
+ /*severe:INVALID_METHOD_OVERRIDE*/A f1; // invalid for getter
+ /*severe:INVALID_METHOD_OVERRIDE*/C f2; // invalid for setter
var f3;
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/dynamic f4;
+ /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic f4;
}
'''
});
@@ -1161,18 +1186,18 @@
}
class GrandChild extends main.Child {
- /*severe:InvalidFieldOverride*/var _f2;
- /*severe:InvalidFieldOverride*/var _f3;
+ /*severe:INVALID_FIELD_OVERRIDE*/var _f2;
+ /*severe:INVALID_FIELD_OVERRIDE*/var _f3;
var _f4;
- /*severe:InvalidMethodOverride*/String _m1();
+ /*severe:INVALID_METHOD_OVERRIDE*/String _m1();
}
''',
'/main.dart': '''
import 'helper.dart' as helper;
class Child extends helper.Base {
- /*severe:InvalidFieldOverride*/var f1;
+ /*severe:INVALID_FIELD_OVERRIDE*/var f1;
var _f2;
var _f4;
@@ -1195,10 +1220,10 @@
}
class Child extends Base {
- /*severe:InvalidMethodOverride*/A get f1 => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
C get f2 => null;
get f3 => null;
- /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
}
'''
});
@@ -1217,17 +1242,17 @@
}
class Child extends Base {
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/A get f1 => null;
- /*severe:InvalidFieldOverride*/C get f2 => null;
- /*severe:InvalidFieldOverride*/get f3 => null;
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/dynamic get f4 => null;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/C get f2 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/get f3 => null;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
}
class Child2 implements Base {
- /*severe:InvalidMethodOverride*/A get f1 => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/A get f1 => null;
C get f2 => null;
get f3 => null;
- /*severe:InvalidMethodOverride*/dynamic get f4 => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/dynamic get f4 => null;
}
'''
});
@@ -1248,9 +1273,9 @@
class Child extends Base {
void set f1(A value) {}
- /*severe:InvalidMethodOverride*/void set f2(C value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
void set f3(value) {}
- /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
set f5(B value) {}
}
'''
@@ -1271,17 +1296,17 @@
}
class Child extends Base {
- /*severe:InvalidFieldOverride*/B get f1 => null;
- /*severe:InvalidFieldOverride*/B get f2 => null;
- /*severe:InvalidFieldOverride*/B get f3 => null;
- /*severe:InvalidFieldOverride*/B get f4 => null;
- /*severe:InvalidFieldOverride*/B get f5 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/B get f1 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/B get f2 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/B get f3 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/B get f4 => null;
+ /*severe:INVALID_FIELD_OVERRIDE*/B get f5 => null;
- /*severe:InvalidFieldOverride*/void set f1(A value) {}
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/void set f2(C value) {}
- /*severe:InvalidFieldOverride*/void set f3(value) {}
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/void set f4(dynamic value) {}
- /*severe:InvalidFieldOverride*/set f5(B value) {}
+ /*severe:INVALID_FIELD_OVERRIDE*/void set f1(A value) {}
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
+ /*severe:INVALID_FIELD_OVERRIDE*/void set f3(value) {}
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
+ /*severe:INVALID_FIELD_OVERRIDE*/set f5(B value) {}
}
class Child2 implements Base {
@@ -1292,9 +1317,9 @@
B get f5 => null;
void set f1(A value) {}
- /*severe:InvalidMethodOverride*/void set f2(C value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/void set f2(C value) {}
void set f3(value) {}
- /*severe:InvalidMethodOverride*/void set f4(dynamic value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/void set f4(dynamic value) {}
set f5(B value) {}
}
'''
@@ -1316,12 +1341,12 @@
}
class Child extends Base {
- /*severe:InvalidMethodOverride*/A m1(A value) {}
- /*severe:InvalidMethodOverride*/C m2(C value) {}
- /*severe:InvalidMethodOverride*/A m3(C value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/A m1(A value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/C m2(C value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/A m3(C value) {}
C m4(A value) {}
m5(value) {}
- /*severe:InvalidMethodOverride*/dynamic m6(dynamic value) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/dynamic m6(dynamic value) {}
}
'''
});
@@ -1342,23 +1367,23 @@
var c = foo();
~a;
- (/*info:DynamicInvoke*/~d);
+ (/*info:DYNAMIC_INVOKE*/~d);
- !/*severe:StaticTypeError*/a;
- !/*info:DynamicCast*/d;
+ !/*severe:STATIC_TYPE_ERROR*/a;
+ !/*info:DYNAMIC_CAST*/d;
-a;
- (/*info:DynamicInvoke*/-d);
+ (/*info:DYNAMIC_INVOKE*/-d);
++a;
--a;
- (/*info:DynamicInvoke*/++d);
- (/*info:DynamicInvoke*/--d);
+ (/*info:DYNAMIC_INVOKE*/++d);
+ (/*info:DYNAMIC_INVOKE*/--d);
a++;
a--;
- (/*info:DynamicInvoke*/d++);
- (/*info:DynamicInvoke*/d--);
+ (/*info:DYNAMIC_INVOKE*/d++);
+ (/*info:DYNAMIC_INVOKE*/d--);
}'''
});
@@ -1390,39 +1415,39 @@
B b = new B();
var c = foo();
a = a * b;
- a = a * /*info:DynamicCast*/c;
+ a = a * /*info:DYNAMIC_CAST*/c;
a = a / b;
a = a ~/ b;
a = a % b;
a = a + b;
- a = a + /*severe:StaticTypeError*/a;
+ a = a + /*severe:STATIC_TYPE_ERROR*/a;
a = a - b;
- b = /*severe:StaticTypeError*/b - b;
+ b = /*severe:STATIC_TYPE_ERROR*/b - b;
a = a << b;
a = a >> b;
a = a & b;
a = a ^ b;
a = a | b;
- c = (/*info:DynamicInvoke*/c + b);
+ c = (/*info:DYNAMIC_INVOKE*/c + b);
String x = 'hello';
int y = 42;
x = x + x;
- x = x + /*info:DynamicCast*/c;
- x = x + /*severe:StaticTypeError*/y;
+ x = x + /*info:DYNAMIC_CAST*/c;
+ x = x + /*severe:STATIC_TYPE_ERROR*/y;
bool p = true;
p = p && p;
- p = p && /*info:DynamicCast*/c;
- p = (/*info:DynamicCast*/c) && p;
- p = (/*info:DynamicCast*/c) && /*info:DynamicCast*/c;
- p = (/*severe:StaticTypeError*/y) && p;
+ p = p && /*info:DYNAMIC_CAST*/c;
+ p = (/*info:DYNAMIC_CAST*/c) && p;
+ p = (/*info:DYNAMIC_CAST*/c) && /*info:DYNAMIC_CAST*/c;
+ p = (/*severe:STATIC_TYPE_ERROR*/y) && p;
p = c == y;
a = a[b];
- a = a[/*info:DynamicCast*/c];
- c = (/*info:DynamicInvoke*/c[b]);
- a[/*severe:StaticTypeError*/y];
+ a = a[/*info:DYNAMIC_CAST*/c];
+ c = (/*info:DYNAMIC_INVOKE*/c[b]);
+ a[/*severe:STATIC_TYPE_ERROR*/y];
}
'''
});
@@ -1458,7 +1483,7 @@
test() {
int x = 0;
x += 5;
- (/*severe:StaticTypeError*/x += 3.14);
+ (/*severe:STATIC_TYPE_ERROR*/x += 3.14);
double y = 0.0;
y += 5;
@@ -1468,43 +1493,43 @@
z += 5;
z += 3.14;
- x = /*info:DownCastImplicit*/x + z;
- x += /*info:DownCastImplicit*/z;
- y = /*info:DownCastImplicit*/y + z;
- y += /*info:DownCastImplicit*/z;
+ x = /*info:DOWN_CAST_IMPLICIT*/x + z;
+ x += /*info:DOWN_CAST_IMPLICIT*/z;
+ y = /*info:DOWN_CAST_IMPLICIT*/y + z;
+ y += /*info:DOWN_CAST_IMPLICIT*/z;
dynamic w = 42;
- x += /*info:DynamicCast*/w;
- y += /*info:DynamicCast*/w;
- z += /*info:DynamicCast*/w;
+ x += /*info:DYNAMIC_CAST*/w;
+ y += /*info:DYNAMIC_CAST*/w;
+ z += /*info:DYNAMIC_CAST*/w;
A a = new A();
B b = new B();
var c = foo();
a = a * b;
a *= b;
- a *= /*info:DynamicCast*/c;
+ a *= /*info:DYNAMIC_CAST*/c;
a /= b;
a ~/= b;
a %= b;
a += b;
- a += /*severe:StaticTypeError*/a;
+ a += /*severe:STATIC_TYPE_ERROR*/a;
a -= b;
- (/*severe:StaticTypeError*/b -= b);
+ (/*severe:STATIC_TYPE_ERROR*/b -= b);
a <<= b;
a >>= b;
a &= b;
a ^= b;
a |= b;
- (/*info:DynamicInvoke*/c += b);
+ (/*info:DYNAMIC_INVOKE*/c += b);
var d = new D();
a[b] += d;
- a[/*info:DynamicCast*/c] += d;
- a[/*severe:StaticTypeError*/z] += d;
- a[b] += /*info:DynamicCast*/c;
- a[b] += /*severe:StaticTypeError*/z;
- (/*info:DynamicInvoke*/(/*info:DynamicInvoke*/c[b]) += d);
+ a[/*info:DYNAMIC_CAST*/c] += d;
+ a[/*severe:STATIC_TYPE_ERROR*/z] += d;
+ a[b] += /*info:DYNAMIC_CAST*/c;
+ a[b] += /*severe:STATIC_TYPE_ERROR*/z;
+ (/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/c[b]) += d);
}
'''
});
@@ -1520,7 +1545,7 @@
var y, z;
Derived()
: y = print('Derived.1'),
- /*severe:InvalidSuperInvocation*/super(),
+ /*severe:INVALID_SUPER_INVOCATION*/super(),
z = print('Derived.2') {
print('Derived.3');
}
@@ -1548,7 +1573,7 @@
'/main.dart': '''
foo() {
for (int i = 0; i < 10; i++) {
- i = /*severe:StaticTypeError*/"hi";
+ i = /*severe:STATIC_TYPE_ERROR*/"hi";
}
}
bar() {
@@ -1570,35 +1595,35 @@
}
class T1 extends Base {
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/B get f => null;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B get f => null;
}
class T2 extends Base {
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/set f(B b) => null;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
}
class T3 extends Base {
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride*/final B f;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/final B f;
}
class T4 extends Base {
// two: one for the getter one for the setter.
- /*severe:InvalidFieldOverride,severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+ /*severe:INVALID_FIELD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B f;
}
class T5 implements Base {
- /*severe:InvalidMethodOverride*/B get f => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/B get f => null;
}
class T6 implements Base {
- /*severe:InvalidMethodOverride*/set f(B b) => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/set f(B b) => null;
}
class T7 implements Base {
- /*severe:InvalidMethodOverride*/final B f;
+ /*severe:INVALID_METHOD_OVERRIDE*/final B f;
}
class T8 implements Base {
// two: one for the getter one for the setter.
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/B f;
+ /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/B f;
}
'''
});
@@ -1613,7 +1638,7 @@
}
class Test extends Base {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1630,8 +1655,8 @@
}
class Test extends Parent {
- /*severe:InvalidMethodOverride*/m(B a) {}
- /*severe:InvalidFieldOverride*/int x;
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
+ /*severe:INVALID_FIELD_OVERRIDE*/int x;
}
'''
});
@@ -1650,7 +1675,7 @@
class Test extends Parent {
// Reported only once
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1664,7 +1689,7 @@
m(A a) {}
}
class Parent extends Grandparent {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
class Test extends Parent {
@@ -1691,9 +1716,9 @@
int x;
}
- class T1 extends Base with /*severe:InvalidMethodOverride*/M1 {}
- class T2 extends Base with /*severe:InvalidMethodOverride*/M1, /*severe:InvalidFieldOverride*/M2 {}
- class T3 extends Base with /*severe:InvalidFieldOverride*/M2, /*severe:InvalidMethodOverride*/M1 {}
+ class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
+ class T2 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M1, /*severe:INVALID_FIELD_OVERRIDE*/M2 {}
+ class T3 extends Base with /*severe:INVALID_FIELD_OVERRIDE*/M2, /*severe:INVALID_METHOD_OVERRIDE*/M1 {}
'''
});
@@ -1715,7 +1740,7 @@
int x;
}
- class T1 extends Base with M1, /*severe:InvalidMethodOverride,severe:InvalidFieldOverride*/M2 {}
+ class T1 extends Base with M1, /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_FIELD_OVERRIDE*/M2 {}
'''
});
@@ -1744,7 +1769,7 @@
}
class T1 extends Base
- with M1, /*severe:InvalidMethodOverride*/M2, M3 {}
+ with M1, /*severe:INVALID_METHOD_OVERRIDE*/M2, M3 {}
'''
});
@@ -1758,7 +1783,7 @@
}
class T1 implements I {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1777,7 +1802,7 @@
}
- class T1 /*severe:InvalidMethodOverride*/extends Base implements I {
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base implements I {
}
'''
});
@@ -1795,7 +1820,7 @@
m(B a) {}
}
- class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I {}
'''
});
@@ -1816,18 +1841,18 @@
m(B a) {}
}
- class T1 /*severe:InvalidMethodOverride*/extends Base
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
implements I1 {}
class T2 extends Base implements I1 {
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+ /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/m(a) {}
}
- class T3 extends Object with /*severe:InvalidMethodOverride*/Base
+ class T3 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/Base
implements I1 {}
class T4 extends Object with Base implements I1 {
- /*severe:InvalidMethodOverride,severe:InvalidMethodOverride*/m(a) {}
+ /*severe:INVALID_METHOD_OVERRIDE,severe:INVALID_METHOD_OVERRIDE*/m(a) {}
}
'''
});
@@ -1845,7 +1870,7 @@
abstract class I2 implements I1 {}
class T1 implements I2 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1860,7 +1885,7 @@
abstract class I2 extends I1 {}
class T1 implements I2 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1875,7 +1900,7 @@
abstract class I2 extends Object with M1 {}
class T1 implements I2 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1890,7 +1915,7 @@
abstract class Base implements I1 {}
class T1 extends Base {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -1932,7 +1957,7 @@
m(B a) {}
}
- class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I2 {
}
'''
@@ -1951,7 +1976,7 @@
m(B a) {}
}
- class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I2 {
}
'''
@@ -1970,7 +1995,7 @@
m(B a) {}
}
- class T1 extends Object with /*severe:InvalidMethodOverride*/M
+ class T1 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I2 {
}
'''
@@ -1989,7 +2014,7 @@
m(B a) {}
}
- class T1 extends Base with /*severe:InvalidMethodOverride*/M {
+ class T1 extends Base with /*severe:INVALID_METHOD_OVERRIDE*/M {
}
'''
});
@@ -2031,7 +2056,7 @@
m(B a) {}
}
- class T1 /*severe:InvalidMethodOverride*/extends Base
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
implements I2 {
}
'''
@@ -2050,7 +2075,7 @@
m(B a) {}
}
- class T1 /*severe:InvalidMethodOverride*/extends Base
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
implements I2 {
}
'''
@@ -2069,7 +2094,7 @@
m(B a) {}
}
- class T1 /*severe:InvalidMethodOverride*/extends Base
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
implements I2 {
}
'''
@@ -2084,7 +2109,7 @@
}
abstract class Base implements I1 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
class T1 extends Base {
@@ -2093,7 +2118,7 @@
// TODO(sigmund): consider tracking overrides in a fine-grain
// manner, then this and the double-overrides would not be
// reported.
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -2107,7 +2132,7 @@
}
class Base implements I1 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
class T1 extends Base {
@@ -2134,7 +2159,7 @@
}
class T1 implements I2 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
'''
});
@@ -2155,12 +2180,12 @@
// Note: no error reported in `extends Base` to avoid duplicating
// the error in T1.
class T1 extends Base implements I1 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
// If there is no error in the class, we do report the error at
// the base class:
- class T2 /*severe:InvalidMethodOverride*/extends Base
+ class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
implements I1 {
}
'''
@@ -2180,10 +2205,10 @@
}
class T1 extends Object with M implements I1 {
- /*severe:InvalidMethodOverride*/m(B a) {}
+ /*severe:INVALID_METHOD_OVERRIDE*/m(B a) {}
}
- class T2 extends Object with /*severe:InvalidMethodOverride*/M
+ class T2 extends Object with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I1 {
}
'''
@@ -2209,10 +2234,10 @@
}
// Note: otherwise both errors would be reported on this line
- class T1 /*severe:InvalidMethodOverride*/extends Parent1
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Parent1
implements I1 {
}
- class T2 /*severe:InvalidMethodOverride*/extends Parent2
+ class T2 /*severe:INVALID_METHOD_OVERRIDE*/extends Parent2
implements I1 {
}
'''
@@ -2239,8 +2264,8 @@
// different.
// TODO(sigmund): should we merge these as well?
class T1 extends Object
- with /*severe:InvalidMethodOverride*/M1
- with /*severe:InvalidMethodOverride*/M2
+ with /*severe:INVALID_METHOD_OVERRIDE*/M1
+ with /*severe:INVALID_METHOD_OVERRIDE*/M2
implements I1 {
}
'''
@@ -2266,8 +2291,8 @@
// Here we want to report both, because the error location is
// different.
// TODO(sigmund): should we merge these as well?
- class T1 /*severe:InvalidMethodOverride*/extends Base
- with /*severe:InvalidMethodOverride*/M
+ class T1 /*severe:INVALID_METHOD_OVERRIDE*/extends Base
+ with /*severe:INVALID_METHOD_OVERRIDE*/M
implements I1 {
}
'''
@@ -2295,18 +2320,18 @@
void main() {
bool b;
- b = /*info:NonGroundTypeCheckInfo*/foo is I2I;
- b = /*info:NonGroundTypeCheckInfo*/foo is D2I;
- b = /*info:NonGroundTypeCheckInfo*/foo is I2D;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is D2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/foo is I2D;
b = foo is D2D;
- b = /*info:NonGroundTypeCheckInfo*/bar is II2I;
- b = /*info:NonGroundTypeCheckInfo*/bar is DI2I;
- b = /*info:NonGroundTypeCheckInfo*/bar is ID2I;
- b = /*info:NonGroundTypeCheckInfo*/bar is II2D;
- b = /*info:NonGroundTypeCheckInfo*/bar is DD2I;
- b = /*info:NonGroundTypeCheckInfo*/bar is DI2D;
- b = /*info:NonGroundTypeCheckInfo*/bar is ID2D;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is II2D;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DD2I;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is DI2D;
+ b = /*info:NON_GROUND_TYPE_CHECK_INFO*/bar is ID2D;
b = bar is DD2D;
// For as, the validity of checks is deferred to runtime.
@@ -2338,22 +2363,24 @@
foo1() async => x;
Future foo2() async => x;
- Future<int> foo3() async => (/*info:DynamicCast*/x);
- Future<int> foo4() async => (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x));
+ Future<int> foo3() async => (/*info:DYNAMIC_CAST*/x);
+ Future<int> foo4() async => (new Future<int>.value(/*info:DYNAMIC_CAST*/x));
+ Future<int> foo5() async => (/*severe:STATIC_TYPE_ERROR*/new Future<String>.value(/*info:DYNAMIC_CAST*/x));
bar1() async { return x; }
Future bar2() async { return x; }
- Future<int> bar3() async { return (/*info:DynamicCast*/x); }
- Future<int> bar4() async { return (/*severe:StaticTypeError*/new Future<int>.value(/*info:DynamicCast*/x)); }
+ Future<int> bar3() async { return (/*info:DYNAMIC_CAST*/x); }
+ Future<int> bar4() async { return (new Future<int>.value(/*info:DYNAMIC_CAST*/x)); }
+ Future<int> bar5() async { return (/*severe:STATIC_TYPE_ERROR*/new Future<String>.value(/*info:DYNAMIC_CAST*/x)); }
int y;
Future<int> z;
void baz() async {
- int a = /*info:DynamicCast*/await x;
+ int a = /*info:DYNAMIC_CAST*/await x;
int b = await y;
int c = await z;
- String d = /*severe:StaticTypeError*/await z;
+ String d = /*severe:STATIC_TYPE_ERROR*/await z;
}
Future<bool> get issue_264 async {
@@ -2361,7 +2388,7 @@
if (new Random().nextBool()) {
return true;
} else {
- return /*severe:StaticTypeError*/new Future<bool>.value(false);
+ return new Future<bool>.value(false);
}
}
'''
@@ -2375,14 +2402,14 @@
bar1() async* { yield x; }
Stream bar2() async* { yield x; }
- Stream<int> bar3() async* { yield (/*info:DynamicCast*/x); }
- Stream<int> bar4() async* { yield (/*severe:StaticTypeError*/new Stream<int>()); }
+ Stream<int> bar3() async* { yield (/*info:DYNAMIC_CAST*/x); }
+ Stream<int> bar4() async* { yield (/*severe:STATIC_TYPE_ERROR*/new Stream<int>()); }
- baz1() async* { yield* (/*info:DynamicCast*/x); }
- Stream baz2() async* { yield* (/*info:DynamicCast*/x); }
- Stream<int> baz3() async* { yield* (/*warning:DownCastComposite*/x); }
+ baz1() async* { yield* (/*info:DYNAMIC_CAST*/x); }
+ Stream baz2() async* { yield* (/*info:DYNAMIC_CAST*/x); }
+ Stream<int> baz3() async* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
Stream<int> baz4() async* { yield* new Stream<int>(); }
- Stream<int> baz5() async* { yield* (/*info:InferredTypeAllocation*/new Stream()); }
+ Stream<int> baz5() async* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Stream()); }
'''
});
@@ -2394,14 +2421,14 @@
bar1() sync* { yield x; }
Iterable bar2() sync* { yield x; }
- Iterable<int> bar3() sync* { yield (/*info:DynamicCast*/x); }
- Iterable<int> bar4() sync* { yield (/*severe:StaticTypeError*/new Iterable<int>()); }
+ Iterable<int> bar3() sync* { yield (/*info:DYNAMIC_CAST*/x); }
+ Iterable<int> bar4() sync* { yield (/*severe:STATIC_TYPE_ERROR*/new Iterable<int>()); }
- baz1() sync* { yield* (/*info:DynamicCast*/x); }
- Iterable baz2() sync* { yield* (/*info:DynamicCast*/x); }
- Iterable<int> baz3() sync* { yield* (/*warning:DownCastComposite*/x); }
+ baz1() sync* { yield* (/*info:DYNAMIC_CAST*/x); }
+ Iterable baz2() sync* { yield* (/*info:DYNAMIC_CAST*/x); }
+ Iterable<int> baz3() sync* { yield* (/*warning:DOWN_CAST_COMPOSITE*/x); }
Iterable<int> baz4() sync* { yield* new Iterable<int>(); }
- Iterable<int> baz5() sync* { yield* (/*info:InferredTypeAllocation*/new Iterable()); }
+ Iterable<int> baz5() sync* { yield* (/*info:INFERRED_TYPE_ALLOCATION*/new Iterable()); }
'''
});
});
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 2a051be..8fe4b37 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -17,7 +17,7 @@
'/main.dart': '''
test1() {
int x = 3;
- x = /*severe:StaticTypeError*/"hi";
+ x = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -27,7 +27,7 @@
'/main.dart': '''
test2() {
var x = 3;
- x = /*severe:StaticTypeError*/"hi";
+ x = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -67,13 +67,13 @@
test1() {
var a = x;
- a = /*severe:StaticTypeError*/"hi";
+ a = /*severe:STATIC_TYPE_ERROR*/"hi";
a = 3;
var b = y;
- b = /*severe:StaticTypeError*/"hi";
+ b = /*severe:STATIC_TYPE_ERROR*/"hi";
b = 4;
var c = z;
- c = /*severe:StaticTypeError*/"hi";
+ c = /*severe:STATIC_TYPE_ERROR*/"hi";
c = 4;
}
@@ -89,13 +89,13 @@
test1() {
var a = x;
- a = /*severe:StaticTypeError*/"hi";
+ a = /*severe:STATIC_TYPE_ERROR*/"hi";
a = 3;
var b = y;
- b = /*severe:StaticTypeError*/"hi";
+ b = /*severe:STATIC_TYPE_ERROR*/"hi";
b = 4;
var c = z;
- c = /*severe:StaticTypeError*/"hi";
+ c = /*severe:STATIC_TYPE_ERROR*/"hi";
c = 4;
}
@@ -118,11 +118,11 @@
test() {
x = "hi";
- y = /*severe:StaticTypeError*/"hi";
+ y = /*severe:STATIC_TYPE_ERROR*/"hi";
A.x = "hi";
- A.y = /*severe:StaticTypeError*/"hi";
+ A.y = /*severe:STATIC_TYPE_ERROR*/"hi";
new A().x2 = "hi";
- new A().y2 = /*severe:StaticTypeError*/"hi";
+ new A().y2 = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -136,8 +136,8 @@
var y = x;
test1() {
- x = /*severe:StaticTypeError*/"hi";
- y = /*severe:StaticTypeError*/"hi";
+ x = /*severe:STATIC_TYPE_ERROR*/"hi";
+ y = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -151,8 +151,8 @@
class B { static var y = A.x; }
test1() {
- A.x = /*severe:StaticTypeError*/"hi";
- B.y = /*severe:StaticTypeError*/"hi";
+ A.x = /*severe:STATIC_TYPE_ERROR*/"hi";
+ B.y = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -286,7 +286,7 @@
x = D.d2;
x = new C().c2;
x = new D().d3;
- x = /*info:DynamicCast*/new D().d4;
+ x = /*info:DYNAMIC_CAST*/new D().d4;
// Similarly if the library contains parts.
@@ -294,7 +294,7 @@
x = E.e2;
x = E.e3;
x = new E().e4;
- x = /*info:DynamicCast*/new E().e5;
+ x = /*info:DYNAMIC_CAST*/new E().e5;
x = new E().e6;
x = F.f1;
x = new F().f2;
@@ -323,28 +323,28 @@
var j = null as B;
test1() {
- a = /*severe:StaticTypeError*/"hi";
+ a = /*severe:STATIC_TYPE_ERROR*/"hi";
a = new B(3);
- b = /*severe:StaticTypeError*/"hi";
+ b = /*severe:STATIC_TYPE_ERROR*/"hi";
b = new B(3);
c1 = [];
- c1 = /*severe:StaticTypeError*/{};
+ c1 = /*severe:STATIC_TYPE_ERROR*/{};
c2 = [];
- c2 = /*severe:StaticTypeError*/{};
+ c2 = /*severe:STATIC_TYPE_ERROR*/{};
d = {};
- d = /*severe:StaticTypeError*/3;
+ d = /*severe:STATIC_TYPE_ERROR*/3;
e = new A();
- e = /*severe:StaticTypeError*/{};
+ e = /*severe:STATIC_TYPE_ERROR*/{};
f = 3;
- f = /*severe:StaticTypeError*/false;
+ f = /*severe:STATIC_TYPE_ERROR*/false;
g = 1;
- g = /*severe:StaticTypeError*/false;
- h = /*severe:StaticTypeError*/false;
+ g = /*severe:STATIC_TYPE_ERROR*/false;
+ h = /*severe:STATIC_TYPE_ERROR*/false;
h = new B();
i = false;
j = new B();
- j = /*severe:StaticTypeError*/false;
- j = /*severe:StaticTypeError*/[];
+ j = /*severe:STATIC_TYPE_ERROR*/false;
+ j = /*severe:STATIC_TYPE_ERROR*/[];
}
'''
});
@@ -373,7 +373,7 @@
a = t1;
i = t2;
b = t3;
- i = /*info:DynamicCast*/t4;
+ i = /*info:DYNAMIC_CAST*/t4;
i = new B().y; // B.y was inferred though
}
'''
@@ -389,7 +389,7 @@
class Bar<T extends Iterable<String>> {
void foo(T t) {
for (var i in t) {
- int x = /*severe:StaticTypeError*/i;
+ int x = /*severe:STATIC_TYPE_ERROR*/i;
}
}
}
@@ -397,7 +397,7 @@
class Baz<T, E extends Iterable<T>, S extends E> {
void foo(S t) {
for (var i in t) {
- int x = /*severe:StaticTypeError*/i;
+ int x = /*severe:STATIC_TYPE_ERROR*/i;
T y = i;
}
}
@@ -406,36 +406,36 @@
test() {
var list = <Foo>[];
for (var x in list) {
- String y = /*severe:StaticTypeError*/x;
+ String y = /*severe:STATIC_TYPE_ERROR*/x;
}
for (dynamic x in list) {
- String y = /*info:DynamicCast*/x;
+ String y = /*info:DYNAMIC_CAST*/x;
}
- for (String x in /*severe:StaticTypeError*/list) {
+ for (String x in /*severe:STATIC_TYPE_ERROR*/list) {
String y = x;
}
var z;
for(z in list) {
- String y = /*info:DynamicCast*/z;
+ String y = /*info:DYNAMIC_CAST*/z;
}
Iterable iter = list;
- for (Foo x in /*warning:DownCastComposite*/iter) {
+ for (Foo x in /*warning:DOWN_CAST_COMPOSITE*/iter) {
var y = x;
}
dynamic iter2 = list;
- for (Foo x in /*warning:DownCastComposite*/iter2) {
+ for (Foo x in /*warning:DOWN_CAST_COMPOSITE*/iter2) {
var y = x;
}
var map = <String, Foo>{};
// Error: map must be an Iterable.
- for (var x in /*severe:StaticTypeError*/map) {
- String y = /*info:DynamicCast*/x;
+ for (var x in /*severe:STATIC_TYPE_ERROR*/map) {
+ String y = /*info:DYNAMIC_CAST*/x;
}
// We're not properly inferring that map.keys is an Iterable<String>
@@ -481,9 +481,9 @@
test() {
dynamic a = new A();
- A b = /*info:DynamicCast*/a;
- print(/*info:DynamicInvoke*/a.x);
- print(/*info:DynamicInvoke*/(/*info:DynamicInvoke*/a.x) + 2);
+ A b = /*info:DYNAMIC_CAST*/a;
+ print(/*info:DYNAMIC_INVOKE*/a.x);
+ print(/*info:DYNAMIC_INVOKE*/(/*info:DYNAMIC_INVOKE*/a.x) + 2);
}
'''
});
@@ -496,10 +496,10 @@
test5() {
var a1 = new A();
- a1.x = /*severe:StaticTypeError*/"hi";
+ a1.x = /*severe:STATIC_TYPE_ERROR*/"hi";
A a2 = new A();
- a2.x = /*severe:StaticTypeError*/"hi";
+ a2.x = /*severe:STATIC_TYPE_ERROR*/"hi";
}
'''
});
@@ -540,11 +540,11 @@
}
class B extends A {
- /*severe:InvalidFieldOverride*/get x => 3;
+ /*severe:INVALID_FIELD_OVERRIDE*/get x => 3;
}
foo() {
- String y = /*severe:StaticTypeError*/new B().x;
+ String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
int z = new B().x;
}
'''
@@ -561,7 +561,7 @@
}
foo() {
- String y = /*severe:StaticTypeError*/new B().x;
+ String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
int z = new B().x;
}
'''
@@ -576,12 +576,12 @@
}
class B implements A<int> {
- /*severe:InvalidMethodOverride*/dynamic get x => 3;
+ /*severe:INVALID_METHOD_OVERRIDE*/dynamic get x => 3;
}
foo() {
- String y = /*info:DynamicCast*/new B().x;
- int z = /*info:DynamicCast*/new B().x;
+ String y = /*info:DYNAMIC_CAST*/new B().x;
+ int z = /*info:DYNAMIC_CAST*/new B().x;
}
'''
});
@@ -595,11 +595,11 @@
class B implements A<int> {
get x => 3;
- get w => /*severe:StaticTypeError*/"hello";
+ get w => /*severe:STATIC_TYPE_ERROR*/"hello";
}
foo() {
- String y = /*severe:StaticTypeError*/new B().x;
+ String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
int z = new B().x;
}
'''
@@ -613,11 +613,11 @@
class B<E> extends A<E> {
E y;
- /*severe:InvalidFieldOverride*/get x => y;
+ /*severe:INVALID_FIELD_OVERRIDE*/get x => y;
}
foo() {
- int y = /*severe:StaticTypeError*/new B<String>().x;
+ int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().x;
String z = new B<String>().x;
}
'''
@@ -646,7 +646,7 @@
}
foo () {
- int y = /*severe:StaticTypeError*/new B().m(null, null);
+ int y = /*severe:STATIC_TYPE_ERROR*/new B().m(null, null);
String z = new B().m(null, null);
}
'''
@@ -669,7 +669,7 @@
}
foo () {
int y = new C().x;
- String y = /*severe:StaticTypeError*/new C().x;
+ String y = /*severe:STATIC_TYPE_ERROR*/new C().x;
}
'''
});
@@ -705,7 +705,7 @@
}
foo () {
- int y = /*severe:StaticTypeError*/new B<String>().m(null, null).value;
+ int y = /*severe:STATIC_TYPE_ERROR*/new B<String>().m(null, null).value;
String z = new B<String>().m(null, null).value;
}
'''
@@ -719,12 +719,12 @@
}
class B implements A {
- /*severe:InvalidMethodOverride*/dynamic get x => 3;
+ /*severe:INVALID_METHOD_OVERRIDE*/dynamic get x => 3;
}
foo() {
- String y = /*info:DynamicCast*/new B().x;
- int z = /*info:DynamicCast*/new B().x;
+ String y = /*info:DYNAMIC_CAST*/new B().x;
+ int z = /*info:DYNAMIC_CAST*/new B().x;
}
'''
});
@@ -748,12 +748,12 @@
}
class C1 implements A, B {
- /*severe:InvalidMethodOverride*/get a => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
}
// Still ambiguous
class C2 implements B, A {
- /*severe:InvalidMethodOverride*/get a => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
}
'''
});
@@ -785,7 +785,7 @@
}
class C2 implements A, B {
- /*severe:InvalidMethodOverride*/get a => null;
+ /*severe:INVALID_METHOD_OVERRIDE*/get a => null;
}
'''
});
@@ -802,8 +802,8 @@
}
foo() {
- String y = /*info:DynamicCast*/new B().x;
- int z = /*info:DynamicCast*/new B().x;
+ String y = /*info:DYNAMIC_CAST*/new B().x;
+ int z = /*info:DYNAMIC_CAST*/new B().x;
}
'''
});
@@ -820,7 +820,7 @@
}
foo() {
- String y = /*severe:StaticTypeError*/new B().x;
+ String y = /*severe:STATIC_TYPE_ERROR*/new B().x;
int z = new B().x;
}
'''
@@ -840,14 +840,14 @@
String s;
int i;
- s = /*info:DynamicCast*/new B().x;
- s = /*severe:StaticTypeError*/new B().y;
+ s = /*info:DYNAMIC_CAST*/new B().x;
+ s = /*severe:STATIC_TYPE_ERROR*/new B().y;
s = new B().z;
- s = /*severe:StaticTypeError*/new B().w;
+ s = /*severe:STATIC_TYPE_ERROR*/new B().w;
- i = /*info:DynamicCast*/new B().x;
+ i = /*info:DYNAMIC_CAST*/new B().x;
i = new B().y;
- i = /*severe:StaticTypeError*/new B().z;
+ i = /*severe:STATIC_TYPE_ERROR*/new B().z;
i = new B().w;
}
'''
@@ -960,9 +960,9 @@
testChecker('downwards inference: miscellaneous', {
'/main.dart': '''
- typedef (T x);
+ typedef T Function2<S, T>(S x);
class A<T> {
- Function2<T> x;
+ Function2<T, T> x;
A(this.x);
}
void main() {
@@ -970,18 +970,18 @@
var x = "hello";
var y = 3;
void f(List<Map<int, String>> l) {};
- f(/*info:InferredTypeLiteral*/[{y: x}]);
+ f(/*info:INFERRED_TYPE_LITERAL*/[/*info:INFERRED_TYPE_LITERAL*/{y: x}]);
}
{
int f(int x) {};
- A<int> a = /*info:InferredTypeAllocation*/new A(f);
+ A<int> a = /*info:INFERRED_TYPE_ALLOCATION*/new A(f);
}
}
'''
});
group('downwards inference on instance creations', () {
- String info = 'info:InferredTypeAllocation';
+ String info = 'info:INFERRED_TYPE_ALLOCATION';
String code = '''
class A<S, T> {
S x;
@@ -1020,59 +1020,59 @@
A<int, String> a1 = /*$info*/new A.named(3, "hello");
A<int, String> a2 = new A<int, String>(3, "hello");
A<int, String> a3 = new A<int, String>.named(3, "hello");
- A<int, String> a4 = /*severe:StaticTypeError*/new A<int, dynamic>(3, "hello");
- A<int, String> a5 = /*severe:StaticTypeError*/new A<dynamic, dynamic>.named(3, "hello");
+ A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new A<int, dynamic>(3, "hello");
+ A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new A<dynamic, dynamic>.named(3, "hello");
}
{
- A<int, String> a0 = /*severe:StaticTypeError*/new A("hello", 3);
- A<int, String> a1 = /*severe:StaticTypeError*/new A.named("hello", 3);
+ A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new A(/*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
+ A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new A.named(/*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
}
{
A<int, String> a0 = /*$info*/new B("hello", 3);
A<int, String> a1 = /*$info*/new B.named("hello", 3);
A<int, String> a2 = new B<String, int>("hello", 3);
A<int, String> a3 = new B<String, int>.named("hello", 3);
- A<int, String> a4 = /*severe:StaticTypeError*/new B<String, dynamic>("hello", 3);
- A<int, String> a5 = /*severe:StaticTypeError*/new B<dynamic, dynamic>.named("hello", 3);
+ A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new B<String, dynamic>("hello", 3);
+ A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new B<dynamic, dynamic>.named("hello", 3);
}
{
- A<int, String> a0 = /*severe:StaticTypeError*/new B(3, "hello");
- A<int, String> a1 = /*severe:StaticTypeError*/new B.named(3, "hello");
+ A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new B(/*severe:STATIC_TYPE_ERROR*/3, /*severe:STATIC_TYPE_ERROR*/"hello");
+ A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new B.named(/*severe:STATIC_TYPE_ERROR*/3, /*severe:STATIC_TYPE_ERROR*/"hello");
}
{
A<int, int> a0 = /*$info*/new C(3);
A<int, int> a1 = /*$info*/new C.named(3);
A<int, int> a2 = new C<int>(3);
A<int, int> a3 = new C<int>.named(3);
- A<int, int> a4 = /*severe:StaticTypeError*/new C<dynamic>(3);
- A<int, int> a5 = /*severe:StaticTypeError*/new C<dynamic>.named(3);
+ A<int, int> a4 = /*severe:STATIC_TYPE_ERROR*/new C<dynamic>(3);
+ A<int, int> a5 = /*severe:STATIC_TYPE_ERROR*/new C<dynamic>.named(3);
}
{
- A<int, int> a0 = /*severe:StaticTypeError*/new C("hello");
- A<int, int> a1 = /*severe:StaticTypeError*/new C.named("hello");
+ A<int, int> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new C(/*severe:STATIC_TYPE_ERROR*/"hello");
+ A<int, int> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(/*severe:STATIC_TYPE_ERROR*/"hello");
}
{
A<int, String> a0 = /*$info*/new D("hello");
A<int, String> a1 = /*$info*/new D.named("hello");
A<int, String> a2 = new D<int, String>("hello");
A<int, String> a3 = new D<String, String>.named("hello");
- A<int, String> a4 = /*severe:StaticTypeError*/new D<num, dynamic>("hello");
- A<int, String> a5 = /*severe:StaticTypeError*/new D<dynamic, dynamic>.named("hello");
+ A<int, String> a4 = /*severe:STATIC_TYPE_ERROR*/new D<num, dynamic>("hello");
+ A<int, String> a5 = /*severe:STATIC_TYPE_ERROR*/new D<dynamic, dynamic>.named("hello");
}
{
- A<int, String> a0 = /*severe:StaticTypeError*/new D(3);
- A<int, String> a1 = /*severe:StaticTypeError*/new D.named(3);
+ A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new D(/*severe:STATIC_TYPE_ERROR*/3);
+ A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new D.named(/*severe:STATIC_TYPE_ERROR*/3);
}
{ // Currently we only allow variable constraints. Test that we reject.
- A<C<int>, String> a0 = /*severe:StaticTypeError*/new E("hello");
+ A<C<int>, String> a0 = /*severe:STATIC_TYPE_ERROR*/new E("hello");
}
{ // Check named and optional arguments
- A<int, String> a0 = /*$info*/new F(3, "hello", a: [3], b: ["hello"]);
- A<int, String> a1 = /*severe:StaticTypeError*/new F(3, "hello", a: ["hello"], b:[3]);
+ A<int, String> a0 = /*$info*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[3], b: /*info:INFERRED_TYPE_LITERAL*/["hello"]);
+ A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new F(3, "hello", a: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"], b: /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3]);
A<int, String> a2 = /*$info*/new F.named(3, "hello", 3, "hello");
A<int, String> a3 = /*$info*/new F.named(3, "hello");
- A<int, String> a4 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello", 3);
- A<int, String> a5 = /*severe:StaticTypeError*/new F.named(3, "hello", "hello");
+ A<int, String> a4 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello", /*severe:STATIC_TYPE_ERROR*/3);
+ A<int, String> a5 = /*info:INFERRED_TYPE_ALLOCATION*/new F.named(3, "hello", /*severe:STATIC_TYPE_ERROR*/"hello");
}
}
''';
@@ -1080,18 +1080,18 @@
});
group('downwards inference on list literals', () {
- String info = "info:InferredTypeLiteral";
+ String info = "info:INFERRED_TYPE_LITERAL";
String code = '''
void foo([List<String> list1 = /*$info*/const [],
- List<String> list2 = /*severe:StaticTypeError*/const [42]]) {
+ List<String> list2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/42]]) {
}
void main() {
{
List<int> l0 = /*$info*/[];
List<int> l1 = /*$info*/[3];
- List<int> l2 = /*severe:StaticTypeError*/["hello"];
- List<int> l3 = /*severe:StaticTypeError*/["hello", 3];
+ List<int> l2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+ List<int> l3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
}
{
List<dynamic> l0 = [];
@@ -1100,22 +1100,22 @@
List<dynamic> l3 = ["hello", 3];
}
{
- List<int> l0 = /*severe:StaticTypeError*/<num>[];
- List<int> l1 = /*severe:StaticTypeError*/<num>[3];
- List<int> l2 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello"];
- List<int> l3 = /*severe:StaticTypeError*/<num>[/*severe:StaticTypeError*/"hello", 3];
+ List<int> l0 = /*severe:STATIC_TYPE_ERROR*/<num>[];
+ List<int> l1 = /*severe:STATIC_TYPE_ERROR*/<num>[3];
+ List<int> l2 = /*severe:STATIC_TYPE_ERROR*/<num>[/*severe:STATIC_TYPE_ERROR*/"hello"];
+ List<int> l3 = /*severe:STATIC_TYPE_ERROR*/<num>[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
}
{
Iterable<int> i0 = /*$info*/[];
Iterable<int> i1 = /*$info*/[3];
- Iterable<int> i2 = /*severe:StaticTypeError*/["hello"];
- Iterable<int> i3 = /*severe:StaticTypeError*/["hello", 3];
+ Iterable<int> i2 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+ Iterable<int> i3 = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3];
}
{
const List<int> c0 = /*$info*/const [];
const List<int> c1 = /*$info*/const [3];
- const List<int> c2 = /*severe:StaticTypeError*/const ["hello"];
- const List<int> c3 = /*severe:StaticTypeError*/const ["hello", 3];
+ const List<int> c2 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello"];
+ const List<int> c3 = /*info:INFERRED_TYPE_LITERAL*/const [/*severe:STATIC_TYPE_ERROR*/"hello", 3];
}
}
''';
@@ -1123,7 +1123,7 @@
});
group('downwards inference on function arguments', () {
- String info = "info:InferredTypeLiteral";
+ String info = "info:INFERRED_TYPE_LITERAL";
String code = '''
void f0(List<int> a) {};
void f1({List<int> a}) {};
@@ -1133,46 +1133,158 @@
void main() {
f0(/*$info*/[]);
f0(/*$info*/[3]);
- f0(/*severe:StaticTypeError*/["hello"]);
- f0(/*severe:StaticTypeError*/["hello", 3]);
+ f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ f0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
f1(a: /*$info*/[]);
f1(a: /*$info*/[3]);
- f1(a: /*severe:StaticTypeError*/["hello"]);
- f1(a: /*severe:StaticTypeError*/["hello", 3]);
+ f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ f1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
f2(/*$info*/[]);
f2(/*$info*/[3]);
- f2(/*severe:StaticTypeError*/["hello"]);
- f2(/*severe:StaticTypeError*/["hello", 3]);
+ f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ f2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
f3(/*$info*/[]);
- f3(/*$info*/[[3]]);
- f3(/*severe:StaticTypeError*/[["hello"]]);
- f3(/*severe:StaticTypeError*/[["hello"], [3]]);
+ f3(/*$info*/[/*$info*/[3]]);
+ f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ f3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
f4(a: /*$info*/[]);
- f4(a: /*$info*/[[3]]);
- f4(a: /*severe:StaticTypeError*/[["hello"]]);
- f4(a: /*severe:StaticTypeError*/[["hello"], [3]]);
+ f4(a: /*$info*/[/*$info*/[3]]);
+ f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ f4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"], /*$info*/[3]]);
+ }
+ ''';
+ testChecker('infer downwards', {'/main.dart': code});
+ });
+
+ group('downwards inference on constructor arguments', () {
+ String info = "info:INFERRED_TYPE_LITERAL";
+ String code = '''
+ class F0 {
+ F0(List<int> a) {};
+ }
+ class F1 {
+ F1({List<int> a}) {};
+ }
+ class F2 {
+ F2(Iterable<int> a) {};
+ }
+ class F3 {
+ F3(Iterable<Iterable<int>> a) {};
+ }
+ class F4 {
+ F4({Iterable<Iterable<int>> a}) {};
+ }
+ void main() {
+ new F0(/*$info*/[]);
+ new F0(/*$info*/[3]);
+ new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F0(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
+ 3]);
+
+ new F1(a: /*$info*/[]);
+ new F1(a: /*$info*/[3]);
+ new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F1(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+ new F2(/*$info*/[]);
+ new F2(/*$info*/[3]);
+ new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F2(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+ new F3(/*$info*/[]);
+ new F3(/*$info*/[/*$info*/[3]]);
+ new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ new F3(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+ /*$info*/[3]]);
+
+ new F4(a: /*$info*/[]);
+ new F4(a: /*$info*/[/*$info*/[3]]);
+ new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ new F4(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+ /*$info*/[3]]);
+ }
+ ''';
+ testChecker('infer downwards', {'/main.dart': code});
+ });
+
+ group('downwards inference on generic constructor arguments', () {
+ String info = "info:INFERRED_TYPE_LITERAL";
+ String code = '''
+ class F0<T> {
+ F0(List<T> a) {};
+ }
+ class F1<T> {
+ F1({List<T> a}) {};
+ }
+ class F2<T> {
+ F2(Iterable<T> a) {};
+ }
+ class F3<T> {
+ F3(Iterable<Iterable<T>> a) {};
+ }
+ class F4<T> {
+ F4({Iterable<Iterable<T>> a}) {};
+ }
+ void main() {
+ new F0<int>(/*$info*/[]);
+ new F0<int>(/*$info*/[3]);
+ new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F0<int>(/*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello",
+ 3]);
+
+ new F1<int>(a: /*$info*/[]);
+ new F1<int>(a: /*$info*/[3]);
+ new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F1<int>(a: /*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+ new F2<int>(/*$info*/[]);
+ new F2<int>(/*$info*/[3]);
+ new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]);
+ new F2<int>(/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello", 3]);
+
+ new F3<int>(/*$info*/[]);
+ new F3<int>(/*$info*/[/*$info*/[3]]);
+ new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ new F3<int>(/*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+ /*$info*/[3]]);
+
+ new F4<int>(a: /*$info*/[]);
+ new F4<int>(a: /*$info*/[/*$info*/[3]]);
+ new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"]]);
+ new F4<int>(a: /*$info*/[/*$info*/[/*severe:STATIC_TYPE_ERROR*/"hello"],
+ /*$info*/[3]]);
+
+ new F3(/*$info*/[]);
+ new F3(/*$info*/[[3]]);
+ new F3(/*$info*/[["hello"]]);
+ new F3(/*$info*/[["hello"], [3]]);
+
+ new F4(a: /*$info*/[]);
+ new F4(a: /*$info*/[[3]]);
+ new F4(a: /*$info*/[["hello"]]);
+ new F4(a: /*$info*/[["hello"], [3]]);
}
''';
testChecker('infer downwards', {'/main.dart': code});
});
group('downwards inference on map literals', () {
- String info = "info:InferredTypeLiteral";
+ String info = "info:INFERRED_TYPE_LITERAL";
String code = '''
void foo([Map<int, String> m1 = /*$info*/const {1: "hello"},
- Map<int, String> m1 = /*severe:StaticTypeError*/const {"hello": "world"}]) {
+ Map<int, String> m1 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "world"}]) {
}
void main() {
{
Map<int, String> l0 = /*$info*/{};
Map<int, String> l1 = /*$info*/{3: "hello"};
- Map<int, String> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
- Map<int, String> l3 = /*severe:StaticTypeError*/{3: 3};
- Map<int, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+ Map<int, String> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+ Map<int, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+ Map<int, String> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
}
{
Map<dynamic, dynamic> l0 = {};
@@ -1185,27 +1297,27 @@
Map<dynamic, String> l0 = /*$info*/{};
Map<dynamic, String> l1 = /*$info*/{3: "hello"};
Map<dynamic, String> l2 = /*$info*/{"hello": "hello"};
- Map<dynamic, String> l3 = /*severe:StaticTypeError*/{3: 3};
- Map<dynamic, String> l4 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+ Map<dynamic, String> l3 = /*$info*/{3: /*severe:STATIC_TYPE_ERROR*/3};
+ Map<dynamic, String> l4 = /*$info*/{3:"hello", "hello": /*severe:STATIC_TYPE_ERROR*/3};
}
{
Map<int, dynamic> l0 = /*$info*/{};
Map<int, dynamic> l1 = /*$info*/{3: "hello"};
- Map<int, dynamic> l2 = /*severe:StaticTypeError*/{"hello": "hello"};
+ Map<int, dynamic> l2 = /*$info*/{(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
Map<int, dynamic> l3 = /*$info*/{3: 3};
- Map<int, dynamic> l3 = /*severe:StaticTypeError*/{3:"hello", "hello": 3};
+ Map<int, dynamic> l4 = /*$info*/{3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): 3};
}
{
- Map<int, String> l0 = /*severe:StaticTypeError*/<num, dynamic>{};
- Map<int, String> l1 = /*severe:StaticTypeError*/<num, dynamic>{3: "hello"};
- Map<int, String> l3 = /*severe:StaticTypeError*/<num, dynamic>{3: 3};
+ Map<int, String> l0 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{};
+ Map<int, String> l1 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{3: "hello"};
+ Map<int, String> l3 = /*severe:STATIC_TYPE_ERROR*/<num, dynamic>{3: 3};
}
{
const Map<int, String> l0 = /*$info*/const {};
const Map<int, String> l1 = /*$info*/const {3: "hello"};
- const Map<int, String> l2 = /*severe:StaticTypeError*/const {"hello": "hello"};
- const Map<int, String> l3 = /*severe:StaticTypeError*/const {3: 3};
- const Map<int, String> l4 = /*severe:StaticTypeError*/const {3:"hello", "hello": 3};
+ const Map<int, String> l2 = /*$info*/const {(/*severe:STATIC_TYPE_ERROR*/"hello"): "hello"};
+ const Map<int, String> l3 = /*$info*/const {3: /*severe:STATIC_TYPE_ERROR*/3};
+ const Map<int, String> l4 = /*$info*/const {3:"hello", (/*severe:STATIC_TYPE_ERROR*/"hello"): /*severe:STATIC_TYPE_ERROR*/3};
}
}
''';
@@ -1218,41 +1330,119 @@
void main () {
{
- Function2<int, String> l0 = (int x) => null;
+ Function2<int, String> l0 = /*info:INFERRED_TYPE_CLOSURE*/(int x) => null;
Function2<int, String> l1 = (int x) => "hello";
- Function2<int, String> l2 = /*severe:StaticTypeError*/(String x) => "hello";
- Function2<int, String> l3 = /*severe:StaticTypeError*/(int x) => 3;
- Function2<int, String> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return 3};
+ Function2<int, String> l2 = /*severe:STATIC_TYPE_ERROR*/(String x) => "hello";
+ Function2<int, String> l3 = /*severe:STATIC_TYPE_ERROR*/(int x) => 3;
+ Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*severe:STATIC_TYPE_ERROR*/3;};
}
{
- Function2<int, String> l0 = /*info:InferredTypeClosure*/(x) => null;
- Function2<int, String> l1 = /*info:InferredTypeClosure*/(x) => "hello";
- Function2<int, String> l2 = /*severe:StaticTypeError*/(x) => 3;
- Function2<int, String> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(x) {return 3};
+ Function2<int, String> l0 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) => null;
+ Function2<int, String> l1 = /*info:INFERRED_TYPE_CLOSURE*/(x) => "hello";
+ Function2<int, String> l2 = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*/(x) => 3;
+ Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) {return /*severe:STATIC_TYPE_ERROR*/3;};
+ Function2<int, String> l4 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) {return /*severe:STATIC_TYPE_ERROR*/x;};
}
{
- Function2<int, List<String>> l0 = (int x) => null;
- Function2<int, List<String>> l1 = /*info:InferredTypeClosure*/(int x) => ["hello"];
- Function2<int, List<String>> l2 = /*severe:StaticTypeError*/(String x) => ["hello"];
- Function2<int, List<String>> l3 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) => [3];
- Function2<int, List<String>> l4 = /*warning:UninferredClosure should be severe:StaticTypeError*/(int x) {return [3]};
+ Function2<int, List<String>> l0 = /*info:INFERRED_TYPE_CLOSURE*/(int x) => null;
+ Function2<int, List<String>> l1 = (int x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+ Function2<int, List<String>> l2 = /*severe:STATIC_TYPE_ERROR*/(String x) => /*info:INFERRED_TYPE_LITERAL*/["hello"];
+ Function2<int, List<String>> l3 = (int x) => /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];
+ Function2<int, List<String>> l4 = /*info:INFERRED_TYPE_CLOSURE*/(int x) {return /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/3];};
}
{
- Function2<int, int> l0 = /*info:InferredTypeClosure*/(x) => x;
- Function2<int, int> l1 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x+1;
- Function2<int, String> l2 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => x;
- Function2<int, String> l3 = /*info:InferredTypeClosure should be severe:StaticTypeError*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
- Function2<String, String> l4 = /*info:InferredTypeClosure*/(x) => /*info:DynamicInvoke should be pass*/x.substring(3);
+ Function2<int, int> l0 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x;
+ Function2<int, int> l1 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x+1;
+ Function2<int, String> l2 = /*info:INFERRED_TYPE_CLOSURE, severe:STATIC_TYPE_ERROR*/(x) => x;
+ Function2<int, String> l3 = /*info:INFERRED_TYPE_CLOSURE, info:INFERRED_TYPE_CLOSURE*/(x) => /*info:DYNAMIC_CAST, info:DYNAMIC_INVOKE*/x.substring(3);
+ Function2<String, String> l4 = /*info:INFERRED_TYPE_CLOSURE*/(x) => x.substring(3);
}
}
'''
});
+ testChecker('downwards inference initializing formal, default formal', {
+ '/main.dart': '''
+ typedef T Function2<S, T>([S x]);
+ class Foo {
+ List<int> x;
+ Foo([this.x = /*info:INFERRED_TYPE_LITERAL*/const [1]]);
+ Foo.named([List<int> x = /*info:INFERRED_TYPE_LITERAL*/const [1]]);
+ }
+ void f([List<int> l = /*info:INFERRED_TYPE_LITERAL*/const [1]]) {}
+// We do this inference in an early task but don't preserve the infos.
+ Function2<List<int>, String> g = /*pass should be info:INFERRED_TYPE_CLOSURE*/([llll = /*info:INFERRED_TYPE_LITERAL*/const [1]]) => "hello";
+'''
+ });
+
+ testChecker('downwards inference async/await', {
+ '/main.dart': '''
+ import 'dart:async';
+ Future<int> test() async {
+ List<int> l0 = /*warning:DOWN_CAST_COMPOSITE should be pass*/await /*pass should be info:INFERRED_TYPE_LITERAL*/[3];
+ List<int> l1 = await /*info:INFERRED_TYPE_ALLOCATION*/new Future.value(/*info:INFERRED_TYPE_LITERAL*/[3]);
+ '''
+ });
+
+ testChecker('downwards inference foreach', {
+ '/main.dart': '''
+ import 'dart:async';
+ void main() {
+ for(int x in /*info:INFERRED_TYPE_LITERAL*/[1, 2, 3]) {
+ }
+ await for(int x in /*info:INFERRED_TYPE_ALLOCATION*/new Stream()) {
+ }
+ }
+ '''
+ });
+
+ testChecker('downwards inference yield/yield*', {
+ '/main.dart': '''
+ import 'dart:async';
+ Stream<List<int>> foo() async* {
+ yield /*info:INFERRED_TYPE_LITERAL*/[];
+ yield /*severe:STATIC_TYPE_ERROR*/new Stream();
+ yield* /*severe:STATIC_TYPE_ERROR*/[];
+ yield* /*info:INFERRED_TYPE_ALLOCATION*/new Stream();
+ }
+
+ Iterable<Map<int, int>> bar() sync* {
+ yield /*info:INFERRED_TYPE_LITERAL*/{};
+ yield /*severe:STATIC_TYPE_ERROR*/new List();
+ yield* /*severe:STATIC_TYPE_ERROR*/{};
+ yield* /*info:INFERRED_TYPE_ALLOCATION*/new List();
+ }
+ '''
+ });
+
+ testChecker('downwards inference, annotations', {
+ '/main.dart': '''
+ class Foo {
+ const Foo(List<String> l);
+ const Foo.named(List<String> l);
+ }
+ @Foo(/*info:INFERRED_TYPE_LITERAL*/const [])
+ class Bar {}
+ @Foo.named(/*info:INFERRED_TYPE_LITERAL*/const [])
+ class Baz {}
+ '''
+ });
+
+ testChecker('downwards inference, assignment statements', {
+ '/main.dart': '''
+ void main() {
+ List<int> l;
+ l = /*info:INFERRED_TYPE_LITERAL*/[/*severe:STATIC_TYPE_ERROR*/"hello"];
+ l = (l = /*info:INFERRED_TYPE_LITERAL*/[1]);
+ }
+'''
+ });
+
testChecker('inferred initializing formal checks default value', {
'/main.dart': '''
class Foo {
var x = 1;
- Foo([this.x = /*severe:StaticTypeError*/"1"]);
+ Foo([this.x = /*severe:STATIC_TYPE_ERROR*/"1"]);
}'''
});
@@ -1274,20 +1464,20 @@
printDouble(min(1.0, 2.0));
// No help for user-defined functions from num->num->num.
- printInt(/*info:DownCastImplicit*/myMax(1, 2));
+ printInt(/*info:DOWN_CAST_IMPLICIT*/myMax(1, 2));
printInt(myMax(1, 2) as int);
// Mixing int and double means return type is num.
- printInt(/*info:DownCastImplicit*/max(1, 2.0));
- printInt(/*info:DownCastImplicit*/min(1, 2.0));
- printDouble(/*info:DownCastImplicit*/max(1, 2.0));
- printDouble(/*info:DownCastImplicit*/min(1, 2.0));
+ printInt(/*info:DOWN_CAST_IMPLICIT*/max(1, 2.0));
+ printInt(/*info:DOWN_CAST_IMPLICIT*/min(1, 2.0));
+ printDouble(/*info:DOWN_CAST_IMPLICIT*/max(1, 2.0));
+ printDouble(/*info:DOWN_CAST_IMPLICIT*/min(1, 2.0));
// Types other than int and double are not accepted.
printInt(
- /*info:DownCastImplicit*/min(
- /*severe:StaticTypeError*/"hi",
- /*severe:StaticTypeError*/"there"));
+ /*info:DOWN_CAST_IMPLICIT*/min(
+ /*severe:STATIC_TYPE_ERROR*/"hi",
+ /*severe:STATIC_TYPE_ERROR*/"there"));
}
'''
});
@@ -1296,7 +1486,7 @@
'/main.dart': '''
import 'dart:async';
- Future<int> make(int x) => (/*info:InferredTypeAllocation*/new Future(() => x));
+ Future<int> make(int x) => (/*info:INFERRED_TYPE_ALLOCATION*/new Future(() => x));
main() {
Iterable<Future<int>> list = <int>[1, 2, 3].map(make);
diff --git a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
index 330801f..360f6c1 100644
--- a/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
+++ b/pkg/analyzer/test/src/task/strong/strong_test_helper.dart
@@ -63,6 +63,7 @@
AnalysisEngine.instance.useTaskModel = true;
var context = AnalysisEngine.instance.createAnalysisContext();
context.analysisOptions.strongMode = true;
+ context.analysisOptions.strongModeHints = true;
context.sourceFactory = new SourceFactory([
new MockDartSdk(mockSdkSources, reportMissing: true).resolver,
@@ -92,6 +93,13 @@
var librarySource = context.getLibrariesContaining(source).single;
var resolved = context.resolveCompilationUnit2(source, librarySource);
+ var analyzerErrors = context
+ .getErrors(source)
+ .errors
+ .where((error) =>
+ error.errorCode.name.startsWith('STRONG_MODE_INFERRED_TYPE'))
+ .toList();
+ errors.addAll(analyzerErrors);
checker.visitCompilationUnit(resolved);
new _ExpectedErrorVisitor(errors).validate(resolved);
@@ -370,6 +378,7 @@
throw new UnsupportedError('not expecting relative urls in dart: mocks');
}
+// TODO(jmesserly): can we reuse the same mock SDK as Analyzer tests?
/// Sample mock SDK sources.
final Map<String, String> mockSdkSources = {
// The list of types below is derived from:
@@ -395,6 +404,7 @@
class String {
String operator +(String other) {}
+ String substring(int len) {}
}
class bool {}
class num {
@@ -419,8 +429,10 @@
const Object proxy = const _Proxy();
class Iterable<E> {
- fold(initialValue, combine(previousValue, E element)) {}
- Iterable map(f(E element)) {}
+ Iterable/*<R>*/ map/*<R>*/(/*=R*/ f(E e));
+
+ /*=R*/ fold/*<R>*/(/*=R*/ initialValue,
+ /*=R*/ combine(/*=R*/ previousValue, E element));
}
class List<E> implements Iterable<E> {
List([int length]);
@@ -434,8 +446,9 @@
class Future<T> {
Future(computation()) {}
Future.value(T t) {}
- Future then(onValue(T value)) {}
- static Future<List> wait(Iterable<Future> futures) {}
+ static Future<List/*<T>*/> wait/*<T>*/(
+ Iterable<Future/*<T>*/> futures) => null;
+ Future/*<R>*/ then/*<R>*/(/*=R*/ onValue(T value)) => null;
}
class Stream<T> {}
''',
@@ -448,8 +461,8 @@
class Random {
bool nextBool() {}
}
- num min(num x, num y) {}
- num max(num x, num y) {}
+ num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
+ num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) => null;
''',
};
@@ -470,7 +483,7 @@
String errorCodeName(ErrorCode errorCode) {
var name = errorCode.name;
- final prefix = 'dev_compiler.';
+ final prefix = 'STRONG_MODE_';
if (name.startsWith(prefix)) {
return name.substring(prefix.length);
} else {
diff --git a/pkg/analyzer/test/utils.dart b/pkg/analyzer/test/utils.dart
index 7c9fbe0..d5d2879 100644
--- a/pkg/analyzer/test/utils.dart
+++ b/pkg/analyzer/test/utils.dart
@@ -4,7 +4,10 @@
library analyzer.test.utils;
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
@@ -12,3 +15,289 @@
groupSep = ' | ';
JavaFile.pathContext = path.posix;
}
+
+/**
+ * The type of an assertion which asserts properties of [T]s.
+ */
+typedef void Asserter<T>(T type);
+
+/**
+ * The type of a function which given an [S], builds an assertion over [T]s.
+ */
+typedef Asserter<T> AsserterBuilder<S, T>(S arg);
+
+/**
+ * The type of a function which given an [S0] and an S1, builds an assertion
+ * over [T]s.
+ */
+typedef Asserter<T> AsserterBuilder2<S0, S1, T>(S0 arg0, S1 arg1);
+
+/**
+ * The type of a function which given an [R] returns an [AsserterBuilder] over
+ * [S]s and [T]s. That is, it returns a function which given an [S], returns
+ * a function over [T]s.
+ */
+typedef AsserterBuilder<S, T> AsserterBuilderBuilder<R, S, T>(R arg);
+
+class AstFinder {
+ /**
+ * Return the declaration of the class with the given [className] in the given
+ * compilation [unit].
+ */
+ static ClassDeclaration getClass(CompilationUnit unit, String className) {
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+ for (CompilationUnitMember unitMember in unitMembers) {
+ if (unitMember is ClassDeclaration && unitMember.name.name == className) {
+ return unitMember;
+ }
+ }
+ fail('No class named $className in ${unit.element.source}');
+ return null;
+ }
+
+ /**
+ * Return the declaration of the constructor with the given [constructorName] in
+ * the class with the given [className] in the given compilation [unit]. If
+ * constructorName is null, return the default constructor;
+ */
+ static ConstructorDeclaration getConstructorInClass(
+ CompilationUnit unit, String className, String constructorName) {
+ ClassDeclaration unitMember = getClass(unit, className);
+ NodeList<ClassMember> classMembers = unitMember.members;
+ for (ClassMember classMember in classMembers) {
+ if (classMember is ConstructorDeclaration) {
+ if (classMember.name?.name == constructorName) {
+ return classMember;
+ }
+ }
+ }
+ fail('No constructor named $constructorName in $className');
+ return null;
+ }
+
+ /**
+ * Return the declaration of the field with the given [fieldName] in the class
+ * with the given [className] in the given compilation [unit].
+ */
+ static VariableDeclaration getFieldInClass(
+ CompilationUnit unit, String className, String fieldName) {
+ ClassDeclaration unitMember = getClass(unit, className);
+ NodeList<ClassMember> classMembers = unitMember.members;
+ for (ClassMember classMember in classMembers) {
+ if (classMember is FieldDeclaration) {
+ NodeList<VariableDeclaration> fields = classMember.fields.variables;
+ for (VariableDeclaration field in fields) {
+ if (field.name.name == fieldName) {
+ return field;
+ }
+ }
+ }
+ }
+ fail('No field named $fieldName in $className');
+ return null;
+ }
+
+ /**
+ * Return the element of the field with the given [fieldName] in the class
+ * with the given [className] in the given compilation [unit].
+ */
+ static FieldElement getFieldInClassElement(
+ CompilationUnit unit, String className, String fieldName) {
+ return getFieldInClass(unit, className, fieldName)?.name?.staticElement;
+ }
+
+ /**
+ * Return the declaration of the method with the given [methodName] in the
+ * class with the given [className] in the given compilation [unit].
+ */
+ static MethodDeclaration getMethodInClass(
+ CompilationUnit unit, String className, String methodName) {
+ ClassDeclaration unitMember = getClass(unit, className);
+ NodeList<ClassMember> classMembers = unitMember.members;
+ for (ClassMember classMember in classMembers) {
+ if (classMember is MethodDeclaration) {
+ if (classMember.name.name == methodName) {
+ return classMember;
+ }
+ }
+ }
+ fail('No method named $methodName in $className');
+ return null;
+ }
+
+ /**
+ * Return the statements in the body of a the method with the given
+ * [methodName] in the class with the given [className] in the given
+ * compilation [unit].
+ */
+ static List<Statement> getStatementsInMethod(
+ CompilationUnit unit, String className, String methodName) {
+ MethodDeclaration method = getMethodInClass(unit, className, methodName);
+ BlockFunctionBody body = method.body;
+ return body.block.statements;
+ }
+
+ /**
+ * Return the statements in the body of the top-level function with the given
+ * [functionName] in the given compilation [unit].
+ */
+ static List<Statement> getStatementsInTopLevelFunction(
+ CompilationUnit unit, String functionName) {
+ FunctionDeclaration function = getTopLevelFunction(unit, functionName);
+ BlockFunctionBody body = function.functionExpression.body;
+ return body.block.statements;
+ }
+
+ /**
+ * Return the declaration of the top-level function with the given
+ * [functionName] in the given compilation [unit].
+ */
+ static FunctionDeclaration getTopLevelFunction(
+ CompilationUnit unit, String functionName) {
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+ for (CompilationUnitMember unitMember in unitMembers) {
+ if (unitMember is FunctionDeclaration) {
+ if (unitMember.name.name == functionName) {
+ return unitMember;
+ }
+ }
+ }
+ fail('No toplevel function named $functionName found');
+ return null;
+ }
+
+ /**
+ * Return the declaration of the top-level variable with the given
+ * [variableName] in the given compilation [unit].
+ */
+ static VariableDeclaration getTopLevelVariable(
+ CompilationUnit unit, String variableName) {
+ NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+ for (CompilationUnitMember unitMember in unitMembers) {
+ if (unitMember is TopLevelVariableDeclaration) {
+ NodeList<VariableDeclaration> variables =
+ unitMember.variables.variables;
+ for (VariableDeclaration variable in variables) {
+ if (variable.name.name == variableName) {
+ return variable;
+ }
+ }
+ }
+ }
+ fail('No toplevel variable named $variableName found');
+ return null;
+ }
+
+ /**
+ * Return the top-level variable element with the given [name].
+ */
+ static TopLevelVariableElement getTopLevelVariableElement(
+ CompilationUnit unit, String name) {
+ return getTopLevelVariable(unit, name)?.name?.staticElement;
+ }
+}
+
+/**
+ * Class for compositionally building up assertions on types
+ */
+class TypeAssertions {
+ // TODO(leafp): Make these matchers.
+ // https://www.dartdocs.org/documentation/matcher/0.12.0%2B1/matcher/Matcher-class.html
+
+ /* Provides primitive types for basic type assertions */
+ final TypeProvider _typeProvider;
+
+ TypeAssertions(this._typeProvider);
+
+ /**
+ * Primitive assertion for the dynamic type
+ */
+ Asserter<DartType> get isDynamic => isType(_typeProvider.dynamicType);
+
+ /**
+ * Primitive assertion for the int type
+ */
+ Asserter<DartType> get isInt => isType(_typeProvider.intType);
+
+ /**
+ * Primitive assertion for the list type
+ */
+ Asserter<DartType> get isList => sameElement(_typeProvider.listType);
+
+ /**
+ * Primitive assertion for the map type
+ */
+ Asserter<DartType> get isMap => sameElement(_typeProvider.mapType);
+
+ /**
+ * Primitive assertion for the num type
+ */
+ Asserter<DartType> get isNum => isType(_typeProvider.numType);
+
+ /**
+ * Primitive assertion for the string type
+ */
+ Asserter<DartType> get isString => isType(_typeProvider.stringType);
+
+ /**
+ * Given a type, produce an assertion that a type has the same element.
+ */
+ Asserter<DartType> hasElement(Element element) =>
+ (DartType type) => expect(element, same(type.element));
+
+ /**
+ * Given assertions for the argument and return types, produce an
+ * assertion over unary function types.
+ */
+ Asserter<DartType> isFunction2Of(
+ Asserter<DartType> argType, Asserter<DartType> returnType) =>
+ (DartType type) {
+ FunctionType fType = (type as FunctionType);
+ argType(fType.normalParameterTypes[0]);
+ returnType(fType.returnType);
+ };
+
+ /**
+ * Given an assertion for the base type and assertions over the type
+ * parameters, produce an assertion over instantations.
+ */
+ AsserterBuilder<List<Asserter<DartType>>, DartType> isInstantiationOf(
+ Asserter<DartType> baseAssert) =>
+ (List<Asserter<DartType>> argAsserts) => (DartType type) {
+ InterfaceType t = (type as InterfaceType);
+ baseAssert(t);
+ List<DartType> typeArguments = t.typeArguments;
+ expect(typeArguments, hasLength(argAsserts.length));
+ for (int i = 0; i < typeArguments.length; i++) {
+ argAsserts[i](typeArguments[i]);
+ }
+ };
+
+ /**
+ * Assert that a type is the List type, and that the given assertion holds
+ * over the type parameter.
+ */
+ Asserter<InterfaceType> isListOf(Asserter<DartType> argAssert) =>
+ isInstantiationOf(isList)([argAssert]);
+
+ /**
+ * Assert that a type is the Map type, and that the given assertions hold
+ * over the type parameters.
+ */
+ Asserter<InterfaceType> isMapOf(
+ Asserter<DartType> argAssert0, Asserter<DartType> argAssert1) =>
+ isInstantiationOf(isMap)([argAssert0, argAssert1]);
+
+ /**
+ * Assert that one type is the same as another
+ */
+ Asserter<DartType> isType(DartType argument) => (DartType t) {
+ expect(t, same(argument));
+ };
+
+ /**
+ * Given a type, produce an assertion that a type has the same element.
+ */
+ Asserter<DartType> sameElement(DartType elementType) =>
+ hasElement(elementType.element);
+}
diff --git a/pkg/analyzer/tool/summary/idl.dart b/pkg/analyzer/tool/summary/idl.dart
index 545dbfc..fa71eec 100644
--- a/pkg/analyzer/tool/summary/idl.dart
+++ b/pkg/analyzer/tool/summary/idl.dart
@@ -125,6 +125,14 @@
* the kind if [PrelinkedReferenceKind.classOrEnum].
*/
PrelinkedReferenceKind kind;
+
+ /**
+ * Integer index indicating which unit in the imported library contains the
+ * definition of the entity. As with indices into [UnlinkedLibrary.units],
+ * zero represents the defining compilation unit, and nonzero values
+ * represent parts in the order of the corresponding `part` declarations.
+ */
+ int unit;
}
/**
@@ -434,7 +442,8 @@
/**
* Information about the units constituting this library. The first unit
- * listed is always the defining compilation unit.
+ * listed is always the defining compilation unit. The remaining units are
+ * listed in the order of their corresponding `part` declarations.
*/
List<UnlinkedUnit> units;
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 4e915c8..7afcf76 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -44,6 +44,7 @@
ComputeLibraryCycleTask -> LIBRARY_CYCLE
ComputeLibraryCycleTask -> LIBRARY_CYCLE_DEPENDENCIES
ComputeLibraryCycleTask -> LIBRARY_CYCLE_UNITS
+ ComputePropagableVariableDependenciesTask -> PROPAGABLE_VARIABLE_DEPENDENCIES
ContainingLibrariesTask -> CONTAINING_LIBRARIES
DART_ERRORS -> LibraryErrorsReadyTask
DART_ERRORS [shape=box]
@@ -54,13 +55,14 @@
EXPORTED_LIBRARIES -> BuildDirectiveElementsTask
EXPORTED_LIBRARIES -> ReadyLibraryElement2Task
EXPORTED_LIBRARIES -> ReadyLibraryElement5Task
+ EXPORTED_LIBRARIES -> ReadyLibraryElement6Task
EXPORTED_LIBRARIES -> ReadyResolvedUnit10Task
- EXPORTED_LIBRARIES -> ReadyResolvedUnit9Task
+ EXPORTED_LIBRARIES -> ReadyResolvedUnit11Task
EXPORTED_LIBRARIES -> ReadyResolvedUnitTask
EXPORTED_LIBRARIES [shape=box]
EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
EXPORT_SOURCE_CLOSURE [shape=box]
- EvaluateUnitConstantsTask -> RESOLVED_UNIT10
+ EvaluateUnitConstantsTask -> RESOLVED_UNIT11
GatherUsedImportedElementsTask -> USED_IMPORTED_ELEMENTS
GatherUsedLocalElementsTask -> USED_LOCAL_ELEMENTS
GenerateHintsTask -> HINTS
@@ -70,8 +72,9 @@
IMPORTED_LIBRARIES -> BuildDirectiveElementsTask
IMPORTED_LIBRARIES -> ReadyLibraryElement2Task
IMPORTED_LIBRARIES -> ReadyLibraryElement5Task
+ IMPORTED_LIBRARIES -> ReadyLibraryElement6Task
IMPORTED_LIBRARIES -> ReadyResolvedUnit10Task
- IMPORTED_LIBRARIES -> ReadyResolvedUnit9Task
+ IMPORTED_LIBRARIES -> ReadyResolvedUnit11Task
IMPORTED_LIBRARIES -> ReadyResolvedUnitTask
IMPORTED_LIBRARIES -> ResolveUnitTypeNamesTask
IMPORTED_LIBRARIES [shape=box]
@@ -85,9 +88,9 @@
INFERRED_STATIC_VARIABLE -> InferStaticVariableTypesInUnitTask
INFERRED_STATIC_VARIABLE [shape=box]
IS_LAUNCHABLE [shape=box]
- InferInstanceMembersInUnitTask -> RESOLVED_UNIT8
+ InferInstanceMembersInUnitTask -> RESOLVED_UNIT9
InferStaticVariableTypeTask -> INFERRED_STATIC_VARIABLE
- InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT6
+ InferStaticVariableTypesInUnitTask -> RESOLVED_UNIT7
LIBRARY_CYCLE [shape=box]
LIBRARY_CYCLE_DEPENDENCIES -> InferInstanceMembersInUnitTask
LIBRARY_CYCLE_DEPENDENCIES -> InferStaticVariableTypeTask
@@ -115,15 +118,21 @@
LIBRARY_ELEMENT4 -> ResolveUnitTypeNamesTask
LIBRARY_ELEMENT4 [shape=box]
LIBRARY_ELEMENT5 -> PartiallyResolveUnitReferencesTask
+ LIBRARY_ELEMENT5 -> PropagateVariableTypesInLibraryTask
LIBRARY_ELEMENT5 -> ReadyLibraryElement5Task
LIBRARY_ELEMENT5 -> ResolveInstanceFieldsInUnitTask
LIBRARY_ELEMENT5 -> ResolveLibraryReferencesTask
- LIBRARY_ELEMENT5 -> ResolveUnitTask
LIBRARY_ELEMENT5 [shape=box]
+ LIBRARY_ELEMENT6 -> PropagateVariableTypesInLibraryClosureTask
+ LIBRARY_ELEMENT6 -> ReadyLibraryElement6Task
+ LIBRARY_ELEMENT6 [shape=box]
+ LIBRARY_ELEMENT7 -> ResolveUnitTask
+ LIBRARY_ELEMENT7 [shape=box]
LIBRARY_ERRORS_READY [shape=box]
LIBRARY_SPECIFIC_UNITS -> GenerateHintsTask
+ LIBRARY_SPECIFIC_UNITS -> PropagateVariableTypesInLibraryTask
LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit10Task
- LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit9Task
+ LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnit11Task
LIBRARY_SPECIFIC_UNITS -> ReadyResolvedUnitTask
LIBRARY_SPECIFIC_UNITS -> ResolveLibraryReferencesTask
LIBRARY_SPECIFIC_UNITS -> ResolveLibraryTypeNamesTask
@@ -142,6 +151,13 @@
PARSED_UNIT [shape=box]
PARSE_ERRORS -> dartErrorsForSource
PARSE_ERRORS [shape=box]
+ PROPAGABLE_VARIABLES_IN_UNIT -> PropagateVariableTypesInUnitTask
+ PROPAGABLE_VARIABLES_IN_UNIT [shape=box]
+ PROPAGABLE_VARIABLE_DEPENDENCIES -> PropagateVariableTypeTask
+ PROPAGABLE_VARIABLE_DEPENDENCIES [shape=box]
+ PROPAGATED_VARIABLE -> PropagateVariableTypeTask
+ PROPAGATED_VARIABLE -> PropagateVariableTypesInUnitTask
+ PROPAGATED_VARIABLE [shape=box]
ParseDartTask -> EXPLICITLY_IMPORTED_LIBRARIES
ParseDartTask -> EXPORTED_LIBRARIES
ParseDartTask -> IMPORTED_LIBRARIES
@@ -152,22 +168,30 @@
ParseDartTask -> SOURCE_KIND
ParseDartTask -> UNITS
PartiallyResolveUnitReferencesTask -> INFERABLE_STATIC_VARIABLES_IN_UNIT
+ PartiallyResolveUnitReferencesTask -> PROPAGABLE_VARIABLES_IN_UNIT
PartiallyResolveUnitReferencesTask -> RESOLVED_UNIT5
+ PropagateVariableTypeTask -> PROPAGATED_VARIABLE
+ PropagateVariableTypesInLibraryClosureTask -> LIBRARY_ELEMENT7
+ PropagateVariableTypesInLibraryTask -> LIBRARY_ELEMENT6
+ PropagateVariableTypesInUnitTask -> RESOLVED_UNIT6
READY_LIBRARY_ELEMENT2 -> ComputeLibraryCycleTask
READY_LIBRARY_ELEMENT2 -> ReadyLibraryElement2Task
READY_LIBRARY_ELEMENT2 [shape=box]
READY_LIBRARY_ELEMENT5 -> PartiallyResolveUnitReferencesTask
READY_LIBRARY_ELEMENT5 -> ReadyLibraryElement5Task
READY_LIBRARY_ELEMENT5 [shape=box]
+ READY_LIBRARY_ELEMENT6 -> PropagateVariableTypesInLibraryClosureTask
+ READY_LIBRARY_ELEMENT6 -> ReadyLibraryElement6Task
+ READY_LIBRARY_ELEMENT6 [shape=box]
READY_RESOLVED_UNIT -> ReadyResolvedUnitTask
READY_RESOLVED_UNIT -> VerifyUnitTask
READY_RESOLVED_UNIT [shape=box]
READY_RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
- READY_RESOLVED_UNIT10 -> StrongModeVerifyUnitTask
+ READY_RESOLVED_UNIT10 -> ResolveLibraryReferencesTask
READY_RESOLVED_UNIT10 [shape=box]
- READY_RESOLVED_UNIT9 -> ReadyResolvedUnit9Task
- READY_RESOLVED_UNIT9 -> ResolveLibraryReferencesTask
- READY_RESOLVED_UNIT9 [shape=box]
+ READY_RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
+ READY_RESOLVED_UNIT11 -> StrongModeVerifyUnitTask
+ READY_RESOLVED_UNIT11 [shape=box]
REFERENCED_NAMES [shape=box]
RESOLVED_UNIT -> GenerateHintsTask
RESOLVED_UNIT -> GenerateLintsTask
@@ -178,9 +202,16 @@
RESOLVED_UNIT1 -> BuildEnumMemberElementsTask
RESOLVED_UNIT1 -> BuildLibraryElementTask
RESOLVED_UNIT1 [shape=box]
+ RESOLVED_UNIT10 -> ComputeConstantDependenciesTask
+ RESOLVED_UNIT10 -> EvaluateUnitConstantsTask
+ RESOLVED_UNIT10 -> GatherUsedImportedElementsTask
+ RESOLVED_UNIT10 -> GatherUsedLocalElementsTask
RESOLVED_UNIT10 -> ReadyResolvedUnit10Task
- RESOLVED_UNIT10 -> StrongModeVerifyUnitTask
+ RESOLVED_UNIT10 -> ResolveLibraryReferencesTask
RESOLVED_UNIT10 [shape=box]
+ RESOLVED_UNIT11 -> ReadyResolvedUnit11Task
+ RESOLVED_UNIT11 -> StrongModeVerifyUnitTask
+ RESOLVED_UNIT11 [shape=box]
RESOLVED_UNIT2 -> ResolveUnitTypeNamesTask
RESOLVED_UNIT2 [shape=box]
RESOLVED_UNIT3 -> ResolveLibraryTypeNamesTask
@@ -189,25 +220,23 @@
RESOLVED_UNIT4 -> PartiallyResolveUnitReferencesTask
RESOLVED_UNIT4 [shape=box]
RESOLVED_UNIT5 -> ComputeInferableStaticVariableDependenciesTask
- RESOLVED_UNIT5 -> InferStaticVariableTypeTask
- RESOLVED_UNIT5 -> InferStaticVariableTypesInUnitTask
+ RESOLVED_UNIT5 -> ComputePropagableVariableDependenciesTask
+ RESOLVED_UNIT5 -> PropagateVariableTypeTask
+ RESOLVED_UNIT5 -> PropagateVariableTypesInUnitTask
RESOLVED_UNIT5 [shape=box]
- RESOLVED_UNIT6 -> ResolveInstanceFieldsInUnitTask
+ RESOLVED_UNIT6 -> InferStaticVariableTypeTask
+ RESOLVED_UNIT6 -> InferStaticVariableTypesInUnitTask
+ RESOLVED_UNIT6 -> PropagateVariableTypesInLibraryTask
RESOLVED_UNIT6 [shape=box]
- RESOLVED_UNIT7 -> InferInstanceMembersInUnitTask
+ RESOLVED_UNIT7 -> ResolveInstanceFieldsInUnitTask
RESOLVED_UNIT7 [shape=box]
RESOLVED_UNIT8 -> InferInstanceMembersInUnitTask
- RESOLVED_UNIT8 -> InferStaticVariableTypeTask
- RESOLVED_UNIT8 -> PartiallyResolveUnitReferencesTask
- RESOLVED_UNIT8 -> ResolveInstanceFieldsInUnitTask
- RESOLVED_UNIT8 -> ResolveUnitTask
RESOLVED_UNIT8 [shape=box]
- RESOLVED_UNIT9 -> ComputeConstantDependenciesTask
- RESOLVED_UNIT9 -> EvaluateUnitConstantsTask
- RESOLVED_UNIT9 -> GatherUsedImportedElementsTask
- RESOLVED_UNIT9 -> GatherUsedLocalElementsTask
- RESOLVED_UNIT9 -> ReadyResolvedUnit9Task
- RESOLVED_UNIT9 -> ResolveLibraryReferencesTask
+ RESOLVED_UNIT9 -> InferInstanceMembersInUnitTask
+ RESOLVED_UNIT9 -> InferStaticVariableTypeTask
+ RESOLVED_UNIT9 -> PartiallyResolveUnitReferencesTask
+ RESOLVED_UNIT9 -> ResolveInstanceFieldsInUnitTask
+ RESOLVED_UNIT9 -> ResolveUnitTask
RESOLVED_UNIT9 [shape=box]
RESOLVE_TYPE_NAMES_ERRORS -> LibraryUnitErrorsTask
RESOLVE_TYPE_NAMES_ERRORS [shape=box]
@@ -215,14 +244,15 @@
RESOLVE_UNIT_ERRORS [shape=box]
ReadyLibraryElement2Task -> READY_LIBRARY_ELEMENT2
ReadyLibraryElement5Task -> READY_LIBRARY_ELEMENT5
+ ReadyLibraryElement6Task -> READY_LIBRARY_ELEMENT6
ReadyResolvedUnit10Task -> READY_RESOLVED_UNIT10
- ReadyResolvedUnit9Task -> READY_RESOLVED_UNIT9
+ ReadyResolvedUnit11Task -> READY_RESOLVED_UNIT11
ReadyResolvedUnitTask -> READY_RESOLVED_UNIT
- ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT7
+ ResolveInstanceFieldsInUnitTask -> RESOLVED_UNIT8
ResolveLibraryReferencesTask -> LIBRARY_ELEMENT
ResolveLibraryReferencesTask -> REFERENCED_NAMES
ResolveLibraryTypeNamesTask -> LIBRARY_ELEMENT5
- ResolveUnitTask -> RESOLVED_UNIT9
+ ResolveUnitTask -> RESOLVED_UNIT10
ResolveUnitTask -> RESOLVE_UNIT_ERRORS
ResolveUnitTypeNamesTask -> RESOLVED_UNIT3
ResolveUnitTypeNamesTask -> RESOLVE_TYPE_NAMES_ERRORS
@@ -248,6 +278,7 @@
TYPE_PROVIDER -> InferInstanceMembersInUnitTask
TYPE_PROVIDER -> InferStaticVariableTypeTask
TYPE_PROVIDER -> PartiallyResolveUnitReferencesTask
+ TYPE_PROVIDER -> PropagateVariableTypeTask
TYPE_PROVIDER -> ResolveInstanceFieldsInUnitTask
TYPE_PROVIDER -> ResolveLibraryTypeNamesTask
TYPE_PROVIDER -> ResolveUnitTask
diff --git a/pkg/analyzer_cli/.gitignore b/pkg/analyzer_cli/.gitignore
new file mode 100644
index 0000000..3a4106f
--- /dev/null
+++ b/pkg/analyzer_cli/.gitignore
@@ -0,0 +1,11 @@
+.buildlog
+.DS_Store
+.idea
+/.packages
+.project
+.pub/
+.settings/
+analyzer_cli.iml
+build/
+packages
+pubspec.lock
diff --git a/pkg/analyzer_cli/CHANGELOG.md b/pkg/analyzer_cli/CHANGELOG.md
new file mode 100644
index 0000000..c4298d7
--- /dev/null
+++ b/pkg/analyzer_cli/CHANGELOG.md
@@ -0,0 +1,16 @@
+# Changelog
+
+## 1.1.1
+
+- Removed outmoded `--url-mapping` command line option.
+
+## 1.1.0
+
+- New `--lints` command line option.
+
+## 0.0.
+
+
+## 0.0.1
+
+- Initial version
diff --git a/pkg/analyzer_cli/README.md b/pkg/analyzer_cli/README.md
new file mode 100644
index 0000000..1652184
--- /dev/null
+++ b/pkg/analyzer_cli/README.md
@@ -0,0 +1,87 @@
+# dartanalyzer
+
+Use _dartanalyzer_ to statically analyze your code at the command line,
+checking for errors and warnings that are specified in the
+[Dart Language Specification](https://www.dartlang.org/docs/spec/).
+DartPad, code editors, and IDEs such as WebStorm use the same
+analysis engine that dartanalyzer uses.
+
+If you want to _contribute_ to the dartanalyzer project, see the
+[contributor docs](https://github.com/dart-lang/analyzer_cli/blob/master/CONTRIBUTOR.md).
+This page contains information about _using_ the dartanalyzer command-line tool.
+
+## Basic usage
+
+Run the analyzer from the top directory of the package.
+Here's an example of testing a Dart file.
+
+```
+dartanalyzer bin/test.dart
+```
+
+## Options
+
+The following are the most commonly used options for dartanalyzer:
+
+* `--packages=`<br>
+ Specify the path to the package resolution configuration file.
+ For more information see
+ [Package Resolution Configuration File](https://github.com/lrhn/dep-pkgspec/blob/master/DEP-pkgspec.md).
+This option cannot be used with `--package-root`.
+
+* `--package-warnings`<br>
+ Show warnings not only for code in the specified .dart file and
+ others in its library, but also for libraries imported with `package:`.
+
+* `--options=`<br>
+ Specify the path to an analysis options file.
+
+* `--lints`<br>
+ Show the results from the linter.
+
+* `--no-hints`<br>
+ Don't show hints for improving the code.
+
+* `--ignore-unrecognized-flags`<br>
+ Rather than printing the help message,
+ ignore any unrecognized command-line flags.
+
+* `--version`<br>
+ Show the analyzer version.
+
+* `-h` _or_ `--help`<br>
+ Show all the command-line options.
+
+The following are advanced options to use with dartanalyzer:
+
+* `-b` _or_ `--batch`<br>
+ Run in batch mode.
+
+* `--dart-sdk=`<br>
+ Specify the directory that contains the Dart SDK.
+
+* `--fatal-warnings`<br>
+ Except for type warnings, treat warnings as fatal.
+
+* `--format=machine`<br>
+ Produce output in a format suitable for parsing.
+
+* `--url-mapping=libraryUri,/path/to/library.dart`<br>
+ Tells the analyzer to use the specified library as the source
+ for that particular import.
+
+The following options are deprecated:
+
+* `-p` _or_ `--package-root=`<br>
+ **Deprecated.** Specify the directory to search for any libraries that are
+ imported using `package:`. _This option is replaced as of Dart 1.12 with
+ `--packages`._
+
+* `--machine`<br>
+ **Deprecated.** Replaced by `--format`.
+
+* `--show-package-warnings`<br>
+ **Deprecated.** Replaced by `--package-warnings`.
+
+* `--show-sdk-warnings`<br>
+ **Deprecated.** Replaced by `--warnings`.
diff --git a/pkg/analyzer_cli/bin/analyzer.dart b/pkg/analyzer_cli/bin/analyzer.dart
new file mode 100644
index 0000000..b0a32fe
--- /dev/null
+++ b/pkg/analyzer_cli/bin/analyzer.dart
@@ -0,0 +1,16 @@
+#!/usr/bin/env dart
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer_cli/src/driver.dart';
+
+
+
+
+/// The entry point for the analyzer.
+void main(List<String> args) {
+ var starter = new Driver();
+ starter.start(args);
+
+}
diff --git a/pkg/analyzer_cli/lib/src/analyzer_impl.dart b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
new file mode 100644
index 0000000..32d5f37
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/analyzer_impl.dart
@@ -0,0 +1,303 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.analyzer_impl;
+
+import 'dart:collection';
+import 'dart:io';
+
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/error_formatter.dart';
+import 'package:analyzer_cli/src/options.dart';
+
+DirectoryBasedDartSdk sdk;
+
+/// The maximum number of sources for which AST structures should be kept in the cache.
+const int _maxCacheSize = 512;
+
+int currentTimeMillis() => new DateTime.now().millisecondsSinceEpoch;
+
+/// Analyzes single library [File].
+class AnalyzerImpl {
+ final CommandLineOptions options;
+ final int startTime;
+
+ final AnalysisContext context;
+ final Source librarySource;
+
+ /// All [Source]s references by the analyzed library.
+ final Set<Source> sources = new Set<Source>();
+
+ /// All [AnalysisErrorInfo]s in the analyzed library.
+ final List<AnalysisErrorInfo> errorInfos = new List<AnalysisErrorInfo>();
+
+ /// [HashMap] between sources and analysis error infos.
+ final HashMap<Source, AnalysisErrorInfo> sourceErrorsMap =
+ new HashMap<Source, AnalysisErrorInfo>();
+
+ /// If the file specified on the command line is part of a package, the name
+ /// of that package. Otherwise `null`. This allows us to analyze the file
+ /// specified on the command line as though it is reached via a "package:"
+ /// URI, but avoid suppressing its output in the event that the user has not
+ /// specified the "--package-warnings" option.
+ String _selfPackageName;
+
+ AnalyzerImpl(this.context, this.librarySource, this.options, this.startTime);
+
+ /// Returns the maximal [ErrorSeverity] of the recorded errors.
+ ErrorSeverity get maxErrorSeverity {
+ var status = ErrorSeverity.NONE;
+ for (AnalysisErrorInfo errorInfo in errorInfos) {
+ for (AnalysisError error in errorInfo.errors) {
+ if (!_isDesiredError(error)) {
+ continue;
+ }
+ var severity = computeSeverity(error, options);
+ status = status.max(severity);
+ }
+ }
+ return status;
+ }
+
+ void addCompilationUnitSource(CompilationUnitElement unit,
+ Set<LibraryElement> libraries, Set<CompilationUnitElement> units) {
+ if (unit == null || units.contains(unit)) {
+ return;
+ }
+ units.add(unit);
+ sources.add(unit.source);
+ }
+
+ void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
+ Set<CompilationUnitElement> units) {
+ if (library == null || !libraries.add(library)) {
+ return;
+ }
+ // Maybe skip library.
+ {
+ UriKind uriKind = library.source.uriKind;
+ // Optionally skip package: libraries.
+ if (!options.showPackageWarnings && _isOtherPackage(library.source.uri)) {
+ return;
+ }
+ // Optionally skip SDK libraries.
+ if (!options.showSdkWarnings && uriKind == UriKind.DART_URI) {
+ return;
+ }
+ }
+ // Add compilation units.
+ addCompilationUnitSource(library.definingCompilationUnit, libraries, units);
+ for (CompilationUnitElement child in library.parts) {
+ addCompilationUnitSource(child, libraries, units);
+ }
+ // Add referenced libraries.
+ for (LibraryElement child in library.importedLibraries) {
+ addLibrarySources(child, libraries, units);
+ }
+ for (LibraryElement child in library.exportedLibraries) {
+ addLibrarySources(child, libraries, units);
+ }
+ }
+
+ /// Treats the [sourcePath] as the top level library and analyzes it using a
+ /// synchronous algorithm over the analysis engine. If [printMode] is `0`,
+ /// then no error or performance information is printed. If [printMode] is `1`,
+ /// then both will be printed. If [printMode] is `2`, then only performance
+ /// information will be printed, and it will be marked as being for a cold VM.
+ ErrorSeverity analyzeSync({int printMode: 1}) {
+ setupForAnalysis();
+ return _analyzeSync(printMode);
+ }
+
+ /// Fills [errorInfos] using [sources].
+ void prepareErrors() {
+ for (Source source in sources) {
+ context.computeErrors(source);
+
+ errorInfos.add(context.getErrors(source));
+ }
+ }
+
+ /// Fills [sources].
+ void prepareSources(LibraryElement library) {
+ var units = new Set<CompilationUnitElement>();
+ var libraries = new Set<LibraryElement>();
+ addLibrarySources(library, libraries, units);
+ }
+
+ /// Setup local fields such as the analysis context for analysis.
+ void setupForAnalysis() {
+ sources.clear();
+ errorInfos.clear();
+ Uri libraryUri = librarySource.uri;
+ if (libraryUri.scheme == 'package' && libraryUri.pathSegments.length > 0) {
+ _selfPackageName = libraryUri.pathSegments[0];
+ }
+ }
+
+ /// The sync version of analysis.
+ ErrorSeverity _analyzeSync(int printMode) {
+ // Don't try to analyze parts.
+ if (context.computeKindOf(librarySource) == SourceKind.PART) {
+ stderr.writeln("Only libraries can be analyzed.");
+ stderr.writeln(
+ "${librarySource.fullName} is a part and can not be analyzed.");
+ return ErrorSeverity.ERROR;
+ }
+ // Resolve library.
+ var libraryElement = context.computeLibraryElement(librarySource);
+ // Prepare source and errors.
+ prepareSources(libraryElement);
+ prepareErrors();
+
+ // Print errors and performance numbers.
+ if (printMode == 1) {
+ _printErrorsAndPerf();
+ } else if (printMode == 2) {
+ _printColdPerf();
+ }
+
+ // Compute max severity and set exitCode.
+ ErrorSeverity status = maxErrorSeverity;
+ if (status == ErrorSeverity.WARNING && options.warningsAreFatal) {
+ status = ErrorSeverity.ERROR;
+ }
+ return status;
+ }
+
+ bool _isDesiredError(AnalysisError error) {
+ if (error.errorCode.type == ErrorType.TODO) {
+ return false;
+ }
+ if (computeSeverity(error, options) == ErrorSeverity.INFO &&
+ options.disableHints) {
+ return false;
+ }
+ return true;
+ }
+
+ /// Determine whether the given URI refers to a package other than the package
+ /// being analyzed.
+ bool _isOtherPackage(Uri uri) {
+ if (uri.scheme != 'package') {
+ return false;
+ }
+ if (_selfPackageName != null &&
+ uri.pathSegments.length > 0 &&
+ uri.pathSegments[0] == _selfPackageName) {
+ return false;
+ }
+ return true;
+ }
+
+ _printColdPerf() {
+ // Print cold VM performance numbers.
+ int totalTime = currentTimeMillis() - startTime;
+ int otherTime = totalTime;
+ for (PerformanceTag tag in PerformanceTag.all) {
+ if (tag != PerformanceTag.UNKNOWN) {
+ int tagTime = tag.elapsedMs;
+ outSink.writeln('${tag.label}-cold:$tagTime');
+ otherTime -= tagTime;
+ }
+ }
+ outSink.writeln('other-cold:$otherTime');
+ outSink.writeln("total-cold:$totalTime");
+ }
+
+ _printErrorsAndPerf() {
+ // The following is a hack. We currently print out to stderr to ensure that
+ // when in batch mode we print to stderr, this is because the prints from
+ // batch are made to stderr. The reason that options.shouldBatch isn't used
+ // is because when the argument flags are constructed in BatchRunner and
+ // passed in from batch mode which removes the batch flag to prevent the
+ // "cannot have the batch flag and source file" error message.
+ StringSink sink = options.machineFormat ? errorSink : outSink;
+
+ // Print errors.
+ ErrorFormatter formatter =
+ new ErrorFormatter(sink, options, _isDesiredError);
+ formatter.formatErrors(errorInfos);
+ }
+
+ /// Compute the severity of the error; however:
+ /// * if [options.enableTypeChecks] is false, then de-escalate checked-mode
+ /// compile time errors to a severity of [ErrorSeverity.INFO].
+ /// * if [options.hintsAreFatal] is true, escalate hints to errors.
+ static ErrorSeverity computeSeverity(
+ AnalysisError error, CommandLineOptions options) {
+ if (!options.enableTypeChecks &&
+ error.errorCode.type == ErrorType.CHECKED_MODE_COMPILE_TIME_ERROR) {
+ return ErrorSeverity.INFO;
+ }
+ if (options.hintsAreFatal && error.errorCode is HintCode) {
+ return ErrorSeverity.ERROR;
+ }
+ return error.errorCode.errorSeverity;
+ }
+
+ /// Return the corresponding package directory or `null` if none is found.
+ static JavaFile getPackageDirectoryFor(JavaFile sourceFile) {
+ // We are going to ask parent file, so get absolute path.
+ sourceFile = sourceFile.getAbsoluteFile();
+ // Look in the containing directories.
+ JavaFile dir = sourceFile.getParentFile();
+ while (dir != null) {
+ JavaFile packagesDir = new JavaFile.relative(dir, "packages");
+ if (packagesDir.exists()) {
+ return packagesDir;
+ }
+ dir = dir.getParentFile();
+ }
+ // Not found.
+ return null;
+ }
+}
+
+/// This [Logger] prints out information comments to [outSink] and error messages
+/// to [errorSink].
+class StdLogger extends Logger {
+ StdLogger();
+
+ @override
+ void logError(String message, [CaughtException exception]) {
+ errorSink.writeln(message);
+ if (exception != null) {
+ errorSink.writeln(exception);
+ }
+ }
+
+ @override
+ void logError2(String message, Object exception) {
+ errorSink.writeln(message);
+ if (exception != null) {
+ errorSink.writeln(exception.toString());
+ }
+ }
+
+ @override
+ void logInformation(String message, [CaughtException exception]) {
+ outSink.writeln(message);
+ if (exception != null) {
+ outSink.writeln(exception);
+ }
+ }
+
+ @override
+ void logInformation2(String message, Object exception) {
+ outSink.writeln(message);
+ if (exception != null) {
+ outSink.writeln(exception.toString());
+ }
+ }
+}
diff --git a/pkg/analyzer_cli/lib/src/bootloader.dart b/pkg/analyzer_cli/lib/src/bootloader.dart
new file mode 100644
index 0000000..726004cb3
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/bootloader.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.bootloader;
+
+import 'dart:async';
+import 'dart:isolate';
+
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/engine.dart' as engine;
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:source_span/source_span.dart';
+import 'package:yaml/src/yaml_node.dart';
+
+const _analyzerPackageName = 'analyzer';
+
+/// Return non-null if there is a validation issue with this plugin.
+String validate(PluginInfo plugin) {
+ var missing = <String>[];
+ if (plugin.className == null) {
+ missing.add('class name');
+ }
+ if (plugin.libraryUri == null) {
+ missing.add('library uri');
+ }
+ if (missing.isEmpty) {
+ // All good.
+ return null;
+ }
+ return 'Plugin ${plugin.name} skipped, config missing: ${missing.join(", ")}';
+}
+
+List<PluginInfo> _validate(Iterable<PluginInfo> plugins) {
+ List<PluginInfo> validated = <PluginInfo>[];
+ plugins.forEach((PluginInfo plugin) {
+ String validation = validate(plugin);
+ if (validation != null) {
+ errorSink.writeln(validation);
+ } else {
+ validated.add(plugin);
+ }
+ });
+ return validated;
+}
+
+/// Source code assembler.
+class Assembler {
+ /// Plugins to configure.
+ final Iterable<PluginInfo> plugins;
+
+ /// Create an assembler for the given plugin [config].
+ Assembler(this.plugins);
+
+ /// A string enumerating required package `import`s.
+ String get enumerateImports =>
+ plugins.map((PluginInfo p) => "import '${p.libraryUri}';").join('\n');
+
+ /// A string listing initialized plugin instances.
+ String get pluginList =>
+ plugins.map((PluginInfo p) => 'new ${p.className}()').join(', ');
+
+ /// Create a file containing a `main()` suitable for loading in spawned
+ /// isolate.
+ String createMain() => _generateMain();
+
+ String _generateMain() => """
+// 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.
+
+// This code was auto-generated, is not intended to be edited, and is subject to
+// significant change. Please see the README file for more information.
+
+import 'package:analyzer_cli/src/driver.dart';
+
+$enumerateImports
+
+void main(List<String> args) {
+ var starter = new Driver();
+ starter.userDefinedPlugins = [$pluginList];
+ starter.start(args);
+}
+""";
+}
+
+/// Given environment information extracted from command-line `args`, creates a
+/// a loadable analyzer "image".
+class BootLoader {
+ /// Emits an error message to [errorSink] if plugin config can't be read.
+ static final ErrorHandler _pluginConfigErrorHandler = (Exception e) {
+ String details;
+ if (e is PluginConfigFormatException) {
+ details = e.message;
+ var node = e.yamlNode;
+ if (node is YamlNode) {
+ SourceLocation location = node.span.start;
+ details += ' (line ${location.line}, column ${location.column})';
+ }
+ } else {
+ details = e.toString();
+ }
+
+ errorSink.writeln('Plugin configuration skipped: $details');
+ };
+
+ /// Reads plugin config info from `.analysis_options`.
+ PluginConfigOptionsProcessor _pluginOptionsProcessor =
+ new PluginConfigOptionsProcessor(_pluginConfigErrorHandler);
+
+ /// Create a loadable analyzer image configured with plugins derived from
+ /// the given analyzer command-line `args`.
+ Image createImage(List<String> args) {
+ // Parse commandline options.
+ CommandLineOptions options = CommandLineOptions.parse(args);
+
+ // Process analysis options file (and notify all interested parties).
+ _processAnalysisOptions(options);
+
+ // TODO(pquitslund): Pass in .packages info
+ return new Image(_pluginOptionsProcessor.config,
+ args: args, packageRootPath: options.packageRootPath);
+ }
+
+ void _processAnalysisOptions(CommandLineOptions options) {
+ // Determine options file path.
+ var filePath = options.analysisOptionsFile ??
+ engine.AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+ try {
+ var file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ AnalysisOptionsProvider analysisOptionsProvider =
+ new AnalysisOptionsProvider();
+ Map<String, YamlNode> options =
+ analysisOptionsProvider.getOptionsFromFile(file);
+ //TODO(pq): thread in proper context.
+ var temporaryContext = new AnalysisContextImpl();
+ _pluginOptionsProcessor.optionsProcessed(temporaryContext, options);
+ } on Exception catch (e) {
+ _pluginOptionsProcessor.onError(e);
+ }
+ }
+}
+
+/// A loadable "image" of a a configured analyzer instance.
+class Image {
+ /// (Optional) package root path.
+ final String packageRootPath;
+
+ /// (Optional) package map.
+ final Map<String, Uri> packages;
+
+ /// (Optional) args to be passed on to the loaded main.
+ final List<String> args;
+
+ /// Plugin configuration.
+ final PluginConfig config;
+
+ /// Create an image with the given [config] and optionally [packages],
+ /// [packageRootPath], and command line [args].
+ Image(this.config, {this.packages, this.packageRootPath, this.args});
+
+ /// Load this image.
+ ///
+ /// Loading an image consists in assembling an analyzer `main()`, configured
+ /// to include the appropriate analyzer plugins as specified in
+ /// `.analyzer_options` which is then run in a spawned isolate.
+ Future load() {
+ List<PluginInfo> plugins = _validate(config.plugins);
+ String mainSource = new Assembler(plugins).createMain();
+
+ Completer completer = new Completer();
+ ReceivePort exitListener = new ReceivePort();
+ exitListener.listen((data) {
+ completer.complete();
+ exitListener.close();
+ });
+
+ Uri uri =
+ Uri.parse('data:application/dart;charset=utf-8,${Uri.encodeComponent(
+ mainSource)}');
+
+ // TODO(pquitslund): update once .packages are supported.
+ String packageRoot =
+ packageRootPath != null ? packageRootPath : './packages';
+ Uri packageUri = new Uri.file(packageRoot);
+
+ Isolate.spawnUri(uri, args, null /* msg */,
+ packageRoot: packageUri, onExit: exitListener.sendPort);
+
+ return completer.future;
+ }
+}
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
new file mode 100644
index 0000000..752cb1e
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -0,0 +1,641 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.driver;
+
+import 'dart:async';
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:analyzer/file_system/file_system.dart' as fileSystem;
+import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/source/package_map_provider.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
+import 'package:analyzer/source/pub_package_map_provider.dart';
+import 'package:analyzer/source/sdk_ext.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/interner.dart';
+import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/java_io.dart';
+import 'package:analyzer/src/generated/sdk_io.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer/src/task/options.dart';
+import 'package:analyzer_cli/src/analyzer_impl.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:linter/src/plugin/linter_plugin.dart';
+import 'package:package_config/discovery.dart' as pkgDiscovery;
+import 'package:package_config/packages.dart' show Packages;
+import 'package:package_config/packages_file.dart' as pkgfile show parse;
+import 'package:package_config/src/packages_impl.dart' show MapPackages;
+import 'package:path/path.dart' as path;
+import 'package:plugin/plugin.dart';
+import 'package:yaml/yaml.dart';
+
+/// The maximum number of sources for which AST structures should be kept in the
+/// cache.
+const int _maxCacheSize = 512;
+
+/// Shared IO sink for standard error reporting.
+///
+/// *Visible for testing.*
+StringSink errorSink = stderr;
+
+/// Shared IO sink for standard out reporting.
+///
+/// *Visible for testing.*
+StringSink outSink = stdout;
+
+/// Test this option map to see if it specifies lint rules.
+bool containsLintRuleEntry(Map<String, YamlNode> options) {
+ var linterNode = options['linter'];
+ return linterNode is YamlMap && linterNode.containsKey('rules');
+}
+
+typedef ErrorSeverity _BatchRunnerHandler(List<String> args);
+
+class Driver {
+ /// The plugins that are defined outside the `analyzer_cli` package.
+ List<Plugin> _userDefinedPlugins = <Plugin>[];
+
+ /// Indicates whether the analyzer is running in batch mode.
+ bool _isBatch;
+
+ /// The context that was most recently created by a call to [_analyzeAll], or
+ /// `null` if [_analyzeAll] hasn't been called yet.
+ AnalysisContext _context;
+
+ /// If [_context] is not `null`, the [CommandLineOptions] that guided its
+ /// creation.
+ CommandLineOptions _previousOptions;
+
+ /// This Driver's current analysis context.
+ ///
+ /// *Visible for testing.*
+ AnalysisContext get context => _context;
+
+ /// Set the [plugins] that are defined outside the `analyzer_cli` package.
+ void set userDefinedPlugins(List<Plugin> plugins) {
+ _userDefinedPlugins = plugins == null ? <Plugin>[] : plugins;
+ }
+
+ /// Use the given command-line [args] to start this analysis driver.
+ void start(List<String> args) {
+ StringUtilities.INTERNER = new MappedInterner();
+
+ _processPlugins();
+
+ // Parse commandline options.
+ CommandLineOptions options = CommandLineOptions.parse(args);
+
+ // Cache options of interest to inform analysis.
+ _setupEnv(options);
+
+ // Do analysis.
+ if (_isBatch) {
+ _BatchRunner.runAsBatch(args, (List<String> args) {
+ CommandLineOptions options = CommandLineOptions.parse(args);
+ return _analyzeAll(options);
+ });
+ } else {
+ ErrorSeverity severity = _analyzeAll(options);
+ // In case of error propagate exit code.
+ if (severity == ErrorSeverity.ERROR) {
+ exitCode = severity.ordinal;
+ }
+ }
+ }
+
+ /// Perform analysis according to the given [options].
+ ErrorSeverity _analyzeAll(CommandLineOptions options) {
+ if (!options.machineFormat) {
+ outSink.writeln("Analyzing ${options.sourceFiles}...");
+ }
+
+ // Create a context, or re-use the previous one.
+ try {
+ _createAnalysisContext(options);
+ } on _DriverError catch (error) {
+ outSink.writeln(error.msg);
+ return ErrorSeverity.ERROR;
+ }
+
+ // Add all the files to be analyzed en masse to the context. Skip any
+ // files that were added earlier (whether explicitly or implicitly) to
+ // avoid causing those files to be unnecessarily re-read.
+ Set<Source> knownSources = _context.sources.toSet();
+ List<Source> sourcesToAnalyze = <Source>[];
+ ChangeSet changeSet = new ChangeSet();
+ for (String sourcePath in options.sourceFiles) {
+ sourcePath = sourcePath.trim();
+ // Check that file exists.
+ if (!new File(sourcePath).existsSync()) {
+ errorSink.writeln('File not found: $sourcePath');
+ exitCode = ErrorSeverity.ERROR.ordinal;
+ //Fail fast; don't analyze more files
+ return ErrorSeverity.ERROR;
+ }
+ // Check that file is Dart file.
+ if (!AnalysisEngine.isDartFileName(sourcePath)) {
+ errorSink.writeln('$sourcePath is not a Dart file');
+ exitCode = ErrorSeverity.ERROR.ordinal;
+ // Fail fast; don't analyze more files.
+ return ErrorSeverity.ERROR;
+ }
+ Source source = _computeLibrarySource(sourcePath);
+ if (!knownSources.contains(source)) {
+ changeSet.addedSource(source);
+ }
+ sourcesToAnalyze.add(source);
+ }
+ _context.applyChanges(changeSet);
+
+ // Analyze the libraries.
+ ErrorSeverity allResult = ErrorSeverity.NONE;
+ var libUris = <Uri>[];
+ var parts = <Source>[];
+ for (Source source in sourcesToAnalyze) {
+ if (context.computeKindOf(source) == SourceKind.PART) {
+ parts.add(source);
+ continue;
+ }
+ ErrorSeverity status = _runAnalyzer(source, options);
+ allResult = allResult.max(status);
+ libUris.add(source.uri);
+ }
+
+ // Check that each part has a corresponding source in the input list.
+ for (Source part in parts) {
+ bool found = false;
+ for (var lib in context.getLibrariesContaining(part)) {
+ if (libUris.contains(lib.uri)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ errorSink.writeln("${part.fullName} is a part and cannot be analyzed.");
+ errorSink.writeln("Please pass in a library that contains this part.");
+ exitCode = ErrorSeverity.ERROR.ordinal;
+ allResult = allResult.max(ErrorSeverity.ERROR);
+ }
+ }
+
+ return allResult;
+ }
+
+ /// Determine whether the context created during a previous call to
+ /// [_analyzeAll] can be re-used in order to analyze using [options].
+ bool _canContextBeReused(CommandLineOptions options) {
+ // TODO(paulberry): add a command-line option that disables context re-use.
+ if (_context == null) {
+ return false;
+ }
+ if (options.packageRootPath != _previousOptions.packageRootPath) {
+ return false;
+ }
+ if (options.packageConfigPath != _previousOptions.packageConfigPath) {
+ return false;
+ }
+ if (!_equalMaps(
+ options.definedVariables, _previousOptions.definedVariables)) {
+ return false;
+ }
+ if (options.log != _previousOptions.log) {
+ return false;
+ }
+ if (options.disableHints != _previousOptions.disableHints) {
+ return false;
+ }
+ if (options.enableStrictCallChecks !=
+ _previousOptions.enableStrictCallChecks) {
+ return false;
+ }
+ if (options.showPackageWarnings != _previousOptions.showPackageWarnings) {
+ return false;
+ }
+ if (options.showSdkWarnings != _previousOptions.showSdkWarnings) {
+ return false;
+ }
+ if (options.lints != _previousOptions.lints) {
+ return false;
+ }
+ if (options.strongMode != _previousOptions.strongMode) {
+ return false;
+ }
+ if (options.enableSuperMixins != _previousOptions.enableSuperMixins) {
+ return false;
+ }
+ return true;
+ }
+
+ /// Decide on the appropriate policy for which files need to be fully parsed
+ /// and which files need to be diet parsed, based on [options], and return an
+ /// [AnalyzeFunctionBodiesPredicate] that implements this policy.
+ AnalyzeFunctionBodiesPredicate _chooseDietParsingPolicy(
+ CommandLineOptions options) {
+ if (_isBatch) {
+ // As analyzer is currently implemented, once a file has been diet
+ // parsed, it can't easily be un-diet parsed without creating a brand new
+ // context and losing caching. In batch mode, we can't predict which
+ // files we'll need to generate errors and warnings for in the future, so
+ // we can't safely diet parse anything.
+ return (Source source) => true;
+ }
+
+ // Determine the set of packages requiring a full parse. Use null to
+ // represent the case where all packages require a full parse.
+ Set<String> packagesRequiringFullParse;
+ if (options.showPackageWarnings) {
+ // We are showing warnings from all packages so all packages require a
+ // full parse.
+ packagesRequiringFullParse = null;
+ } else {
+ // We aren't showing warnings for dependent packages, but we may still
+ // need to show warnings for "self" packages, so we need to do a full
+ // parse in any package containing files mentioned on the command line.
+ // TODO(paulberry): implement this. As a temporary workaround, we're
+ // fully parsing all packages.
+ packagesRequiringFullParse = null;
+ }
+ return (Source source) {
+ if (source.uri.scheme == 'dart') {
+ return options.showSdkWarnings;
+ } else if (source.uri.scheme == 'package') {
+ if (packagesRequiringFullParse == null) {
+ return true;
+ } else if (source.uri.pathSegments.length == 0) {
+ // We should never see a URI like this, but fully parse it to be
+ // safe.
+ return true;
+ } else {
+ return packagesRequiringFullParse
+ .contains(source.uri.pathSegments[0]);
+ }
+ } else {
+ return true;
+ }
+ };
+ }
+
+ /// Decide on the appropriate method for resolving URIs based on the given
+ /// [options] and [customUrlMappings] settings, and return a
+ /// [SourceFactory] that has been configured accordingly.
+ SourceFactory _chooseUriResolutionPolicy(CommandLineOptions options) {
+ Packages packages;
+ Map<String, List<fileSystem.Folder>> packageMap;
+ UriResolver packageUriResolver;
+
+ // Process options, caching package resolution details.
+ if (options.packageConfigPath != null) {
+ String packageConfigPath = options.packageConfigPath;
+ Uri fileUri = new Uri.file(packageConfigPath);
+ try {
+ File configFile = new File.fromUri(fileUri).absolute;
+ List<int> bytes = configFile.readAsBytesSync();
+ Map<String, Uri> map = pkgfile.parse(bytes, configFile.uri);
+ packages = new MapPackages(map);
+ packageMap = _getPackageMap(packages);
+ } catch (e) {
+ printAndFail(
+ 'Unable to read package config data from $packageConfigPath: $e');
+ }
+ } else if (options.packageRootPath != null) {
+ packageMap = _PackageRootPackageMapBuilder
+ .buildPackageMap(options.packageRootPath);
+
+ JavaFile packageDirectory = new JavaFile(options.packageRootPath);
+ packageUriResolver = new PackageUriResolver([packageDirectory]);
+ } else {
+ fileSystem.Resource cwd =
+ PhysicalResourceProvider.INSTANCE.getResource('.');
+
+ // Look for .packages.
+ packages = _discoverPackagespec(new Uri.directory(cwd.path));
+
+ if (packages != null) {
+ packageMap = _getPackageMap(packages);
+ } else {
+ // Fall back to pub list-package-dirs.
+
+ PubPackageMapProvider pubPackageMapProvider =
+ new PubPackageMapProvider(PhysicalResourceProvider.INSTANCE, sdk);
+ PackageMapInfo packageMapInfo =
+ pubPackageMapProvider.computePackageMap(cwd);
+ packageMap = packageMapInfo.packageMap;
+
+ // Only create a packageUriResolver if pub list-package-dirs succeeded.
+ // If it failed, that's not a problem; it simply means we have no way
+ // to resolve packages.
+ if (packageMapInfo.packageMap != null) {
+ packageUriResolver = new PackageMapUriResolver(
+ PhysicalResourceProvider.INSTANCE, packageMap);
+ }
+ }
+ }
+
+ // Now, build our resolver list.
+
+ // 'dart:' URIs come first.
+ List<UriResolver> resolvers = [new DartUriResolver(sdk)];
+
+ // Next SdkExts.
+ if (packageMap != null) {
+ resolvers.add(new SdkExtUriResolver(packageMap));
+ }
+
+ // Then package URIs.
+ if (packageUriResolver != null) {
+ resolvers.add(packageUriResolver);
+ }
+
+ // Finally files.
+ resolvers.add(new FileUriResolver());
+
+ return new SourceFactory(resolvers, packages);
+ }
+
+ /// Convert the given [sourcePath] (which may be relative to the current
+ /// working directory) to a [Source] object that can be fed to the analysis
+ /// context.
+ Source _computeLibrarySource(String sourcePath) {
+ sourcePath = _normalizeSourcePath(sourcePath);
+ JavaFile sourceFile = new JavaFile(sourcePath);
+ Source source = sdk.fromFileUri(sourceFile.toURI());
+ if (source != null) {
+ return source;
+ }
+ source = new FileBasedSource(sourceFile, sourceFile.toURI());
+ Uri uri = _context.sourceFactory.restoreUri(source);
+ if (uri == null) {
+ return source;
+ }
+ return new FileBasedSource(sourceFile, uri);
+ }
+
+ /// Create an analysis context that is prepared to analyze sources according
+ /// to the given [options], and store it in [_context].
+ void _createAnalysisContext(CommandLineOptions options) {
+ if (_canContextBeReused(options)) {
+ return;
+ }
+ _previousOptions = options;
+ // Choose a package resolution policy and a diet parsing policy based on
+ // the command-line options.
+ SourceFactory sourceFactory = _chooseUriResolutionPolicy(options);
+ AnalyzeFunctionBodiesPredicate dietParsingPolicy =
+ _chooseDietParsingPolicy(options);
+ // Create a context using these policies.
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+
+ context.sourceFactory = sourceFactory;
+
+ Map<String, String> definedVariables = options.definedVariables;
+ if (!definedVariables.isEmpty) {
+ DeclaredVariables declaredVariables = context.declaredVariables;
+ definedVariables.forEach((String variableName, String value) {
+ declaredVariables.define(variableName, value);
+ });
+ }
+
+ if (options.log) {
+ AnalysisEngine.instance.logger = new StdLogger();
+ }
+
+ // Set context options.
+ AnalysisOptionsImpl contextOptions = new AnalysisOptionsImpl();
+ contextOptions.cacheSize = _maxCacheSize;
+ contextOptions.hint = !options.disableHints;
+ contextOptions.enableStrictCallChecks = options.enableStrictCallChecks;
+ contextOptions.enableSuperMixins = options.enableSuperMixins;
+ contextOptions.analyzeFunctionBodiesPredicate = dietParsingPolicy;
+ contextOptions.generateImplicitErrors = options.showPackageWarnings;
+ contextOptions.generateSdkErrors = options.showSdkWarnings;
+ contextOptions.lint = options.lints;
+ contextOptions.strongMode = options.strongMode;
+ context.analysisOptions = contextOptions;
+ _context = context;
+
+ // Process analysis options file (and notify all interested parties).
+ _processAnalysisOptions(options, context);
+ }
+
+ /// Return discovered packagespec, or `null` if none is found.
+ Packages _discoverPackagespec(Uri root) {
+ try {
+ Packages packages = pkgDiscovery.findPackagesFromFile(root);
+ if (packages != Packages.noPackages) {
+ return packages;
+ }
+ } catch (_) {
+ // Ignore and fall through to null.
+ }
+
+ return null;
+ }
+
+ fileSystem.File _getOptionsFile(CommandLineOptions options) {
+ fileSystem.File file;
+ String filePath = options.analysisOptionsFile;
+ if (filePath != null) {
+ file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ if (!file.exists) {
+ printAndFail('Options file not found: $filePath',
+ exitCode: ErrorSeverity.ERROR.ordinal);
+ }
+ } else {
+ filePath = AnalysisEngine.ANALYSIS_OPTIONS_FILE;
+ file = PhysicalResourceProvider.INSTANCE.getFile(filePath);
+ }
+ return file;
+ }
+
+ Map<String, List<fileSystem.Folder>> _getPackageMap(Packages packages) {
+ if (packages == null) {
+ return null;
+ }
+
+ Map<String, List<fileSystem.Folder>> folderMap =
+ new Map<String, List<fileSystem.Folder>>();
+ packages.asMap().forEach((String packagePath, Uri uri) {
+ folderMap[packagePath] = [
+ PhysicalResourceProvider.INSTANCE.getFolder(path.fromUri(uri))
+ ];
+ });
+ return folderMap;
+ }
+
+ void _processAnalysisOptions(
+ CommandLineOptions options, AnalysisContext context) {
+ fileSystem.File file = _getOptionsFile(options);
+ List<OptionsProcessor> optionsProcessors =
+ AnalysisEngine.instance.optionsPlugin.optionsProcessors;
+ try {
+ AnalysisOptionsProvider analysisOptionsProvider =
+ new AnalysisOptionsProvider();
+ Map<String, YamlNode> optionMap =
+ analysisOptionsProvider.getOptionsFromFile(file);
+ optionsProcessors.forEach(
+ (OptionsProcessor p) => p.optionsProcessed(context, optionMap));
+
+ // Fill in lint rule defaults in case lints are enabled and rules are
+ // not specified in an options file.
+ if (options.lints && !containsLintRuleEntry(optionMap)) {
+ setLints(context, linterPlugin.contributedRules);
+ }
+
+ // Ask engine to further process options.
+ if (optionMap != null) {
+ configureContextOptions(context, optionMap);
+ }
+ } on Exception catch (e) {
+ optionsProcessors.forEach((OptionsProcessor p) => p.onError(e));
+ }
+ }
+
+ void _processPlugins() {
+ List<Plugin> plugins = <Plugin>[];
+ plugins.add(linterPlugin);
+ plugins.addAll(_userDefinedPlugins);
+ AnalysisEngine.instance.userDefinedPlugins = plugins;
+
+ // This ensures that AE extension manager processes plugins.
+ AnalysisEngine.instance.taskManager;
+ }
+
+ /// Analyze a single source.
+ ErrorSeverity _runAnalyzer(Source source, CommandLineOptions options) {
+ int startTime = currentTimeMillis();
+ AnalyzerImpl analyzer =
+ new AnalyzerImpl(_context, source, options, startTime);
+ var errorSeverity = analyzer.analyzeSync();
+ if (errorSeverity == ErrorSeverity.ERROR) {
+ exitCode = errorSeverity.ordinal;
+ }
+ if (options.warningsAreFatal && errorSeverity == ErrorSeverity.WARNING) {
+ exitCode = errorSeverity.ordinal;
+ }
+ return errorSeverity;
+ }
+
+ void _setupEnv(CommandLineOptions options) {
+ // In batch mode, SDK is specified on the main command line rather than in
+ // the command lines sent to stdin. So process it before deciding whether
+ // to activate batch mode.
+ if (sdk == null) {
+ sdk = new DirectoryBasedDartSdk(new JavaFile(options.dartSdkPath));
+ }
+ _isBatch = options.shouldBatch;
+ }
+
+ /// Perform a deep comparison of two string maps.
+ static bool _equalMaps(Map<String, String> m1, Map<String, String> m2) {
+ if (m1.length != m2.length) {
+ return false;
+ }
+ for (String key in m1.keys) {
+ if (!m2.containsKey(key) || m1[key] != m2[key]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /// Convert [sourcePath] into an absolute path.
+ static String _normalizeSourcePath(String sourcePath) =>
+ path.normalize(new File(sourcePath).absolute.path);
+}
+
+/// Provides a framework to read command line options from stdin and feed them
+/// to a callback.
+class _BatchRunner {
+ /// Run the tool in 'batch' mode, receiving command lines through stdin and
+ /// returning pass/fail status through stdout. This feature is intended for
+ /// use in unit testing.
+ static void runAsBatch(List<String> sharedArgs, _BatchRunnerHandler handler) {
+ outSink.writeln('>>> BATCH START');
+ Stopwatch stopwatch = new Stopwatch();
+ stopwatch.start();
+ int testsFailed = 0;
+ int totalTests = 0;
+ ErrorSeverity batchResult = ErrorSeverity.NONE;
+ // Read line from stdin.
+ Stream cmdLine =
+ stdin.transform(UTF8.decoder).transform(new LineSplitter());
+ cmdLine.listen((String line) {
+ // Maybe finish.
+ if (line.isEmpty) {
+ var time = stopwatch.elapsedMilliseconds;
+ outSink.writeln(
+ '>>> BATCH END (${totalTests - testsFailed}/$totalTests) ${time}ms');
+ exitCode = batchResult.ordinal;
+ }
+ // Prepare aruments.
+ var args;
+ {
+ var lineArgs = line.split(new RegExp('\\s+'));
+ args = new List<String>();
+ args.addAll(sharedArgs);
+ args.addAll(lineArgs);
+ args.remove('-b');
+ args.remove('--batch');
+ }
+ // Analyze single set of arguments.
+ try {
+ totalTests++;
+ ErrorSeverity result = handler(args);
+ bool resultPass = result != ErrorSeverity.ERROR;
+ if (!resultPass) {
+ testsFailed++;
+ }
+ batchResult = batchResult.max(result);
+ // Write stderr end token and flush.
+ errorSink.writeln('>>> EOF STDERR');
+ String resultPassString = resultPass ? 'PASS' : 'FAIL';
+ outSink.writeln(
+ '>>> TEST $resultPassString ${stopwatch.elapsedMilliseconds}ms');
+ } catch (e, stackTrace) {
+ errorSink.writeln(e);
+ errorSink.writeln(stackTrace);
+ errorSink.writeln('>>> EOF STDERR');
+ outSink.writeln('>>> TEST CRASH');
+ }
+ });
+ }
+}
+
+class _DriverError implements Exception {
+ String msg;
+ _DriverError(this.msg);
+}
+
+/// [SdkExtUriResolver] needs a Map from package name to folder. In the case
+/// that the analyzer is invoked with a --package-root option, we need to
+/// manually create this mapping. Given [packageRootPath],
+/// [_PackageRootPackageMapBuilder] creates a simple mapping from package name
+/// to full path on disk (resolving any symbolic links).
+class _PackageRootPackageMapBuilder {
+ static Map<String, List<fileSystem.Folder>> buildPackageMap(
+ String packageRootPath) {
+ var packageRoot = new Directory(packageRootPath);
+ if (!packageRoot.existsSync()) {
+ throw new _DriverError(
+ 'Package root directory ($packageRootPath) does not exist.');
+ }
+ var packages = packageRoot.listSync(followLinks: false);
+ var result = new Map<String, List<fileSystem.Folder>>();
+ for (var package in packages) {
+ var packageName = path.basename(package.path);
+ var realPath = package.resolveSymbolicLinksSync();
+ result[packageName] = [
+ PhysicalResourceProvider.INSTANCE.getFolder(realPath)
+ ];
+ }
+ return result;
+ }
+}
diff --git a/pkg/analyzer_cli/lib/src/error_formatter.dart b/pkg/analyzer_cli/lib/src/error_formatter.dart
new file mode 100644
index 0000000..fe0f00f
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/error_formatter.dart
@@ -0,0 +1,196 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.error_formatter;
+
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_cli/src/analyzer_impl.dart';
+import 'package:analyzer_cli/src/options.dart';
+
+/// Allows any [AnalysisError].
+bool _anyError(AnalysisError error) => true;
+
+/// Returns `true` if [AnalysisError] should be printed.
+typedef bool _ErrorFilter(AnalysisError error);
+
+/// Helper for formatting [AnalysisError]s.
+/// The two format options are a user consumable format and a machine consumable format.
+class ErrorFormatter {
+ final StringSink out;
+ final CommandLineOptions options;
+ final _ErrorFilter errorFilter;
+
+ ErrorFormatter(this.out, this.options, [this.errorFilter = _anyError]);
+
+ void formatError(
+ Map<AnalysisError, LineInfo> errorToLine, AnalysisError error) {
+ Source source = error.source;
+ LineInfo_Location location = errorToLine[error].getLocation(error.offset);
+ int length = error.length;
+ ErrorSeverity severity =
+ AnalyzerImpl.computeSeverity(error, options);
+ if (options.machineFormat) {
+ if (severity == ErrorSeverity.WARNING && options.warningsAreFatal) {
+ severity = ErrorSeverity.ERROR;
+ }
+ out.write(severity);
+ out.write('|');
+ out.write(error.errorCode.type);
+ out.write('|');
+ out.write(error.errorCode.name);
+ out.write('|');
+ out.write(escapePipe(source.fullName));
+ out.write('|');
+ out.write(location.lineNumber);
+ out.write('|');
+ out.write(location.columnNumber);
+ out.write('|');
+ out.write(length);
+ out.write('|');
+ out.write(escapePipe(error.message));
+ } else {
+ String errorType = severity.displayName;
+ if (error.errorCode.type == ErrorType.HINT ||
+ error.errorCode.type == ErrorType.LINT) {
+ errorType = error.errorCode.type.displayName;
+ }
+ // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
+ out.write('[$errorType] ${error.message} ');
+ out.write('(${source.fullName}');
+ out.write(', line ${location.lineNumber}, col ${location.columnNumber})');
+ }
+ out.writeln();
+ }
+
+ void formatErrors(List<AnalysisErrorInfo> errorInfos) {
+ var errors = new List<AnalysisError>();
+ var errorToLine = new Map<AnalysisError, LineInfo>();
+ for (AnalysisErrorInfo errorInfo in errorInfos) {
+ for (AnalysisError error in errorInfo.errors) {
+ if (errorFilter(error)) {
+ errors.add(error);
+ errorToLine[error] = errorInfo.lineInfo;
+ }
+ }
+ }
+ // Sort errors.
+ errors.sort((AnalysisError error1, AnalysisError error2) {
+ // Severity.
+ ErrorSeverity severity1 =
+ AnalyzerImpl.computeSeverity(error1, options);
+ ErrorSeverity severity2 =
+ AnalyzerImpl.computeSeverity(error2, options);
+ int compare = severity2.compareTo(severity1);
+ if (compare != 0) {
+ return compare;
+ }
+ // Path.
+ compare = Comparable.compare(error1.source.fullName.toLowerCase(),
+ error2.source.fullName.toLowerCase());
+ if (compare != 0) {
+ return compare;
+ }
+ // Offset.
+ return error1.offset - error2.offset;
+ });
+ // Format errors.
+ int errorCount = 0;
+ int warnCount = 0;
+ int hintCount = 0;
+ int lintCount = 0;
+ for (AnalysisError error in errors) {
+ ErrorSeverity severity =
+ AnalyzerImpl.computeSeverity(error, options);
+ if (severity == ErrorSeverity.ERROR) {
+ errorCount++;
+ } else if (severity == ErrorSeverity.WARNING) {
+ if (options.warningsAreFatal) {
+ errorCount++;
+ } else {
+ warnCount++;
+ }
+ } else if (error.errorCode.type == ErrorType.HINT) {
+ hintCount++;
+ } else if (error.errorCode.type == ErrorType.LINT) {
+ lintCount++;
+ }
+ formatError(errorToLine, error);
+ }
+ // Print statistics.
+ if (!options.machineFormat) {
+ var hasErrors = errorCount != 0;
+ var hasWarns = warnCount != 0;
+ var hasHints = hintCount != 0;
+ var hasLints = lintCount != 0;
+ bool hasContent = false;
+ if (hasErrors) {
+ out.write(errorCount);
+ out.write(' ');
+ out.write(pluralize("error", errorCount));
+ hasContent = true;
+ }
+ if (hasWarns) {
+ if (hasContent) {
+ if (!hasHints && !hasLints) {
+ out.write(' and ');
+ } else {
+ out.write(", ");
+ }
+ }
+ out.write(warnCount);
+ out.write(' ');
+ out.write(pluralize("warning", warnCount));
+ hasContent = true;
+ }
+ if (hasHints) {
+ if (hasContent) {
+ if (!hasLints) {
+ out.write(' and ');
+ } else {
+ out.write(", ");
+ }
+ }
+ out.write(hintCount);
+ out.write(' ');
+ out.write(pluralize("hint", hintCount));
+ hasContent = true;
+ }
+ if (hasLints) {
+ if (hasContent) {
+ out.write(" and ");
+ }
+ out.write(lintCount);
+ out.write(' ');
+ out.write(pluralize("lint", lintCount));
+ hasContent = true;
+ }
+ if (hasContent) {
+ out.writeln(" found.");
+ } else {
+ out.writeln("No issues found");
+ }
+ }
+ }
+
+ static String escapePipe(String input) {
+ var result = new StringBuffer();
+ for (var c in input.codeUnits) {
+ if (c == '\\' || c == '|') {
+ result.write('\\');
+ }
+ result.writeCharCode(c);
+ }
+ return result.toString();
+ }
+
+ static String pluralize(String word, int count) {
+ if (count == 1) {
+ return word;
+ } else {
+ return word + "s";
+ }
+ }
+}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
new file mode 100644
index 0000000..ee683e2
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -0,0 +1,485 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.options;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:args/args.dart';
+import 'package:cli_util/cli_util.dart' show getSdkDir;
+
+const _binaryName = 'dartanalyzer';
+
+/// Shared exit handler.
+///
+/// *Visible for testing.*
+ExitHandler exitHandler = exit;
+
+/// Print the given message to stderr and exit with the given [exitCode]
+void printAndFail(String message, {int exitCode: 15}) {
+ errorSink.writeln(message);
+ exitHandler(exitCode);
+}
+
+/// Exit handler.
+///
+/// *Visible for testing.*
+typedef void ExitHandler(int code);
+
+/// Analyzer commandline configuration options.
+class CommandLineOptions {
+ /// The path to an analysis options file
+ final String analysisOptionsFile;
+
+ /// The path to the dart SDK
+ String dartSdkPath;
+
+ /// A table mapping the names of defined variables to their values.
+ final Map<String, String> definedVariables;
+
+ /// Whether to report hints
+ final bool disableHints;
+
+ /// Whether to display version information
+ final bool displayVersion;
+
+ /// Whether to enable null-aware operators (DEP 9).
+ final bool enableNullAwareOperators;
+
+ /// Whether to strictly follow the specification when generating warnings on
+ /// "call" methods (fixes dartbug.com/21938).
+ final bool enableStrictCallChecks;
+
+ /// Whether to relax restrictions on mixins (DEP 34).
+ final bool enableSuperMixins;
+
+ /// Whether to treat type mismatches found during constant evaluation as
+ /// errors.
+ final bool enableTypeChecks;
+
+ /// Whether to treat hints as fatal
+ final bool hintsAreFatal;
+
+ /// Whether to ignore unrecognized flags
+ final bool ignoreUnrecognizedFlags;
+
+ /// Whether to report lints
+ final bool lints;
+
+ /// Whether to log additional analysis messages and exceptions
+ final bool log;
+
+ /// Whether to use machine format for error display
+ final bool machineFormat;
+
+ /// The path to the package root
+ final String packageRootPath;
+
+ /// The path to a `.packages` configuration file
+ final String packageConfigPath;
+
+ /// Batch mode (for unit testing)
+ final bool shouldBatch;
+
+ /// Whether to show package: warnings
+ final bool showPackageWarnings;
+
+ /// Whether to show SDK warnings
+ final bool showSdkWarnings;
+
+ /// The source files to analyze
+ final List<String> sourceFiles;
+
+ /// Whether to treat warnings as fatal
+ final bool warningsAreFatal;
+
+ /// Whether to use strong static checking.
+ final bool strongMode;
+
+ /// Initialize options from the given parsed [args].
+ CommandLineOptions._fromArgs(
+ ArgResults args, Map<String, String> definedVariables)
+ : dartSdkPath = args['dart-sdk'],
+ this.definedVariables = definedVariables,
+ analysisOptionsFile = args['options'],
+ disableHints = args['no-hints'],
+ displayVersion = args['version'],
+ enableNullAwareOperators = args['enable-null-aware-operators'],
+ enableStrictCallChecks = args['enable-strict-call-checks'],
+ enableSuperMixins = args['supermixin'],
+ enableTypeChecks = args['enable_type_checks'],
+ hintsAreFatal = args['fatal-hints'],
+ ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
+ lints = args['lints'],
+ log = args['log'],
+ machineFormat = args['machine'] || args['format'] == 'machine',
+ packageConfigPath = args['packages'],
+ packageRootPath = args['package-root'],
+ shouldBatch = args['batch'],
+ showPackageWarnings =
+ args['show-package-warnings'] || args['package-warnings'],
+ showSdkWarnings = args['show-sdk-warnings'] || args['warnings'],
+ sourceFiles = args.rest,
+ warningsAreFatal = args['fatal-warnings'],
+ strongMode = args['strong'];
+
+ /// Parse [args] into [CommandLineOptions] describing the specified
+ /// analyzer options. In case of a format error, calls [printAndFail], which
+ /// by default prints an error message to stderr and exits.
+ static CommandLineOptions parse(List<String> args,
+ [printAndFail = printAndFail]) {
+ CommandLineOptions options = _parse(args);
+ // Check SDK.
+ {
+ // Infer if unspecified.
+ if (options.dartSdkPath == null) {
+ Directory sdkDir = getSdkDir(args);
+ if (sdkDir != null) {
+ options.dartSdkPath = sdkDir.path;
+ }
+ }
+
+ var sdkPath = options.dartSdkPath;
+
+ // Check that SDK is specified.
+ if (sdkPath == null) {
+ printAndFail('No Dart SDK found.');
+ }
+ // Check that SDK is existing directory.
+ if (!(new Directory(sdkPath)).existsSync()) {
+ printAndFail('Invalid Dart SDK path: $sdkPath');
+ }
+ }
+
+ // Check package config.
+ {
+ if (options.packageRootPath != null &&
+ options.packageConfigPath != null) {
+ printAndFail("Cannot specify both '--package-root' and '--packages.");
+ }
+ }
+
+ // OK. Report deprecated options.
+ if (options.enableNullAwareOperators) {
+ stderr.writeln(
+ "Info: Option '--enable-null-aware-operators' is no longer needed. Null aware operators are supported by default.");
+ }
+
+ return options;
+ }
+
+ static String _getVersion() {
+ try {
+ // This is relative to bin/snapshot, so ../..
+ String versionPath =
+ Platform.script.resolve('../../version').toFilePath();
+ File versionFile = new File(versionPath);
+ return versionFile.readAsStringSync().trim();
+ } catch (_) {
+ // This happens when the script is not running in the context of an SDK.
+ return "<unknown>";
+ }
+ }
+
+ static CommandLineOptions _parse(List<String> args) {
+ args = args.expand((String arg) => arg.split('=')).toList();
+ var parser = new CommandLineParser()
+ ..addFlag('batch',
+ abbr: 'b',
+ help: 'Read commands from standard input (for testing).',
+ defaultsTo: false,
+ negatable: false)
+ ..addOption('dart-sdk', help: 'The path to the Dart SDK.')
+ ..addOption('packages',
+ help:
+ 'Path to the package resolution configuration file, which supplies a mapping of package names to paths. This option cannot be used with --package-root.')
+ ..addOption('package-root',
+ abbr: 'p',
+ help:
+ 'Path to a package root directory (deprecated). This option cannot be used with --packages.')
+ ..addOption('options', help: 'Path to an analysis options file.')
+ ..addOption('format',
+ help: 'Specifies the format in which errors are displayed.')
+ ..addFlag('machine',
+ help: 'Print errors in a format suitable for parsing (deprecated).',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('version',
+ help: 'Print the analyzer version.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('lints',
+ help: 'Show lint results.', defaultsTo: false, negatable: false)
+ ..addFlag('no-hints',
+ help: 'Do not show hint results.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('ignore-unrecognized-flags',
+ help: 'Ignore unrecognized command line flags.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('fatal-hints',
+ help: 'Treat hints as fatal.', defaultsTo: false, negatable: false)
+ ..addFlag('fatal-warnings',
+ help: 'Treat non-type warnings as fatal.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('package-warnings',
+ help: 'Show warnings from package: imports.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('show-package-warnings',
+ help: 'Show warnings from package: imports (deprecated).',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('warnings',
+ help: 'Show warnings from SDK imports.',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('show-sdk-warnings',
+ help: 'Show warnings from SDK imports (deprecated).',
+ defaultsTo: false,
+ negatable: false)
+ ..addFlag('help',
+ abbr: 'h',
+ help: 'Display this help message.',
+ defaultsTo: false,
+ negatable: false)
+ ..addOption('url-mapping',
+ help: '--url-mapping=libraryUri,/path/to/library.dart directs the '
+ 'analyzer to use "library.dart" as the source for an import '
+ 'of "libraryUri".',
+ allowMultiple: true,
+ splitCommas: false)
+ //
+ // Hidden flags.
+ //
+ ..addFlag('enable-async',
+ help: 'Enable support for the proposed async feature.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('enable-enum',
+ help: 'Enable support for the proposed enum feature.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('enable-null-aware-operators',
+ help: 'Enable support for null-aware operators (DEP 9).',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('enable-strict-call-checks',
+ help: 'Fix issue 21938.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('enable-new-task-model',
+ help: 'Ennable new task model.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('supermixin',
+ help: 'Relax restrictions on mixins (DEP 34).',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('log',
+ help: 'Log additional messages and exceptions.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('enable_type_checks',
+ help: 'Check types in constant evaluation.',
+ defaultsTo: false,
+ negatable: false,
+ hide: true)
+ ..addFlag('strong',
+ help: 'Enable strong static checks (https://goo.gl/DqcBsw)');
+
+ try {
+ // TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061
+ args =
+ args.map((String arg) => arg == '-batch' ? '--batch' : arg).toList();
+ Map<String, String> definedVariables = <String, String>{};
+ var results = parser.parse(args, definedVariables);
+ // Help requests.
+ if (results['help']) {
+ _showUsage(parser);
+ exit(0);
+ }
+ // Batch mode and input files.
+ if (results['batch']) {
+ if (results.rest.isNotEmpty) {
+ stderr.writeln('No source files expected in the batch mode.');
+ _showUsage(parser);
+ exit(15);
+ }
+ } else if (results['version']) {
+ print('$_binaryName version ${_getVersion()}');
+ exit(0);
+ } else {
+ if (results.rest.isEmpty) {
+ _showUsage(parser);
+ exit(15);
+ }
+ }
+ return new CommandLineOptions._fromArgs(results, definedVariables);
+ } on FormatException catch (e) {
+ stderr.writeln(e.message);
+ _showUsage(parser);
+ exit(15);
+ }
+ }
+
+ static _showUsage(parser) {
+ stderr
+ .writeln('Usage: $_binaryName [options...] <libraries to analyze...>');
+ stderr.writeln(parser.getUsage());
+ stderr.writeln('');
+ stderr.writeln(
+ 'For more information, see http://www.dartlang.org/tools/analyzer.');
+ }
+}
+
+/// Commandline argument parser.
+///
+/// TODO(pquitslund): when the args package supports ignoring unrecognized
+/// options/flags, this class can be replaced with a simple [ArgParser]
+/// instance.
+class CommandLineParser {
+ final List<String> _knownFlags;
+ final bool _alwaysIgnoreUnrecognized;
+ final ArgParser _parser;
+
+ /// Creates a new command line parser.
+ CommandLineParser({bool alwaysIgnoreUnrecognized: false})
+ : _knownFlags = <String>[],
+ _alwaysIgnoreUnrecognized = alwaysIgnoreUnrecognized,
+ _parser = new ArgParser(allowTrailingOptions: true);
+
+ ArgParser get parser => _parser;
+
+ /// Defines a flag.
+ /// See [ArgParser.addFlag()].
+ void addFlag(String name,
+ {String abbr,
+ String help,
+ bool defaultsTo: false,
+ bool negatable: true,
+ void callback(bool value),
+ bool hide: false}) {
+ _knownFlags.add(name);
+ _parser.addFlag(name,
+ abbr: abbr,
+ help: help,
+ defaultsTo: defaultsTo,
+ negatable: negatable,
+ callback: callback,
+ hide: hide);
+ }
+
+ /// Defines a value-taking option.
+ /// See [ArgParser.addOption()].
+ void addOption(String name,
+ {String abbr,
+ String help,
+ List<String> allowed,
+ Map<String, String> allowedHelp,
+ String defaultsTo,
+ void callback(value),
+ bool allowMultiple: false,
+ bool splitCommas}) {
+ _knownFlags.add(name);
+ _parser.addOption(name,
+ abbr: abbr,
+ help: help,
+ allowed: allowed,
+ allowedHelp: allowedHelp,
+ defaultsTo: defaultsTo,
+ callback: callback,
+ allowMultiple: allowMultiple,
+ splitCommas: splitCommas);
+ }
+
+ /// Generates a string displaying usage information for the defined options.
+ /// See [ArgParser.usage].
+ String getUsage() => _parser.usage;
+
+ /// Parses [args], a list of command-line arguments, matches them against the
+ /// flags and options defined by this parser, and returns the result. The
+ /// values of any defined variables are captured in the given map.
+ /// See [ArgParser].
+ ArgResults parse(List<String> args, Map<String, String> definedVariables) =>
+ _parser.parse(
+ _filterUnknowns(parseDefinedVariables(args, definedVariables)));
+
+ List<String> parseDefinedVariables(
+ List<String> args, Map<String, String> definedVariables) {
+ int count = args.length;
+ List<String> remainingArgs = <String>[];
+ for (int i = 0; i < count; i++) {
+ String arg = args[i];
+ if (arg == '--') {
+ while (i < count) {
+ remainingArgs.add(args[i++]);
+ }
+ } else if (arg.startsWith("-D")) {
+ definedVariables[arg.substring(2)] = args[++i];
+ } else {
+ remainingArgs.add(arg);
+ }
+ }
+ return remainingArgs;
+ }
+
+ List<String> _filterUnknowns(List<String> args) {
+ // Only filter args if the ignore flag is specified, or if
+ // _alwaysIgnoreUnrecognized was set to true.
+ if (_alwaysIgnoreUnrecognized ||
+ args.contains('--ignore-unrecognized-flags')) {
+ //TODO(pquitslund): replace w/ the following once library skew issues are
+ // sorted out
+ //return args.where((arg) => !arg.startsWith('--') ||
+ // _knownFlags.contains(arg.substring(2)));
+
+ // Filter all unrecognized flags and options.
+ List<String> filtered = <String>[];
+ for (int i = 0; i < args.length; ++i) {
+ String arg = args[i];
+ if (arg.startsWith('--') && arg.length > 2) {
+ String option = arg.substring(2);
+ // strip the last '=value'
+ int equalsOffset = option.lastIndexOf('=');
+ if (equalsOffset != -1) {
+ option = option.substring(0, equalsOffset);
+ }
+ // Check the option
+ if (!_knownFlags.contains(option)) {
+ //"eat" params by advancing to the next flag/option
+ i = _getNextFlagIndex(args, i);
+ } else {
+ filtered.add(arg);
+ }
+ } else {
+ filtered.add(arg);
+ }
+ }
+
+ return filtered;
+ } else {
+ return args;
+ }
+ }
+
+ int _getNextFlagIndex(args, i) {
+ for (; i < args.length; ++i) {
+ if (args[i].startsWith('--')) {
+ return i;
+ }
+ }
+ return i;
+ }
+}
diff --git a/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
new file mode 100644
index 0000000..13a8202
--- /dev/null
+++ b/pkg/analyzer_cli/lib/src/plugin/plugin_manager.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.src.plugin.plugin_manager;
+
+import 'dart:io';
+
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:path/path.dart' as path;
+
+const _manifestFileName = 'plugins.yaml';
+
+/// Given a local configuration (as defined in `.analysis_options`)
+/// and information from a plugin manifest, return plugin info
+/// appropriate for configuring this plugin.
+PluginInfo combine(PluginInfo localConfig, PluginInfo manifestInfo) {
+ return new PluginInfo(
+ name: localConfig.name,
+ version: manifestInfo.version,
+ className: manifestInfo.className,
+ libraryUri: manifestInfo.libraryUri);
+}
+
+/// Call-back to allow for the injection of manifest readers that do not need
+/// to go to disk (for testing purposes).
+typedef String ManifestReader(Uri uri);
+
+/// Wraps a [plugin] info object elaborated with any configuration information
+/// extracted from an associated manifest and [status].
+class PluginDetails {
+ /// Plugin status.
+ final PluginStatus status;
+
+ /// Plugin info.
+ final PluginInfo plugin;
+
+ /// Wrap a [plugin] with [status] info.
+ PluginDetails(this.plugin) : status = PluginStatus.Applicable;
+ PluginDetails.notApplicable(this.plugin)
+ : status = PluginStatus.NotApplicable;
+ PluginDetails.notFound(this.plugin) : status = PluginStatus.NotFound;
+}
+
+/// Manages plugin information derived from plugin manifests.
+class PluginManager {
+ /// Mapping from package name to package location.
+ final Map<String, Uri> _packageMap;
+
+ /// The package naming the app to host plugins.
+ final String hostPackage;
+
+ /// Function to perform the reading of manifest URIs. (For testing.)
+ ManifestReader _manifestReader;
+
+ /// Create a plugin manager with backing package map information.
+ PluginManager(this._packageMap, this.hostPackage,
+ [ManifestReader manifestReader]) {
+ _manifestReader =
+ manifestReader != null ? manifestReader : _findAndReadManifestAtUri;
+ }
+
+ /// Find a plugin manifest describing the given [pluginPackage].
+ PluginManifest findManifest(String pluginPackage) {
+ Uri uri = _packageMap[pluginPackage];
+ String contents = _manifestReader(uri);
+ if (contents == null) {
+ return null;
+ }
+ return parsePluginManifestString(contents);
+ }
+
+ /// Return [PluginDetails] derived from associated plugin manifests
+ /// corresponding to plugins specified in the given [config].
+ Iterable<PluginDetails> getPluginDetails(PluginConfig config) =>
+ config.plugins.map((PluginInfo localConfig) {
+ PluginManifest manifest = findManifest(localConfig.name);
+ return _getDetails(localConfig, manifest);
+ });
+
+ String _findAndReadManifestAtUri(Uri uri) {
+ File manifestFile = _findManifest(uri);
+ return manifestFile?.readAsStringSync();
+ }
+
+ File _findManifest(Uri uri) {
+ if (uri == null) {
+ return null;
+ }
+
+ Directory directory = new Directory.fromUri(uri);
+ File file = new File(path.join(directory.path, _manifestFileName));
+
+ return file.existsSync() ? file : null;
+ }
+
+ PluginDetails _getDetails(PluginInfo localConfig, PluginManifest manifest) {
+ if (manifest == null) {
+ return new PluginDetails.notFound(localConfig);
+ }
+ if (!manifest.contributesTo.contains(hostPackage)) {
+ return new PluginDetails.notApplicable(localConfig);
+ }
+
+ return new PluginDetails(combine(localConfig, manifest.plugin));
+ }
+}
+
+/// Describes plugin status.
+enum PluginStatus { Applicable, NotApplicable, NotFound }
diff --git a/pkg/analyzer_cli/pubspec.yaml b/pkg/analyzer_cli/pubspec.yaml
new file mode 100644
index 0000000..bc255ee
--- /dev/null
+++ b/pkg/analyzer_cli/pubspec.yaml
@@ -0,0 +1,18 @@
+name: analyzer_cli
+version: 1.1.2
+author: Dart Team <misc@dartlang.org>
+description: Command line interface for the Dart Analyzer.
+homepage: https://github.com/dart-lang/analyzer_cli
+environment:
+ sdk: '>=1.12.0 <2.0.0'
+dependencies:
+ analyzer: ^0.26.1+17
+ args: ^0.13.0
+ cli_util: ^0.0.1
+ linter: ^0.1.3+4
+ package_config: ^0.1.1
+ plugin: ^0.1.0
+ yaml: ^2.1.2
+dev_dependencies:
+ typed_mock: '>=0.0.4 <1.0.0'
+ unittest: '>=0.9.0 <0.12.0'
diff --git a/pkg/analyzer_cli/test/all.dart b/pkg/analyzer_cli/test/all.dart
new file mode 100644
index 0000000..5b08f58
--- /dev/null
+++ b/pkg/analyzer_cli/test/all.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'driver_test.dart' as driver;
+import 'error_test.dart' as error;
+import 'options_test.dart' as options;
+import 'plugin_manager_test.dart' as plugin_manager;
+import 'reporter_test.dart' as reporter;
+import 'sdk_ext_test.dart' as sdk_ext;
+import 'strong_mode_test.dart' as strong_mode;
+import 'super_mixin_test.dart' as super_mixin;
+
+main() {
+ // TODO(pq): fix tests to run safely on the bots
+ // https://github.com/dart-lang/sdk/issues/25001
+ //driver.main();
+ //sdk_ext.main();
+ //strong_mode.main();
+ error.main();
+ options.main();
+ plugin_manager.main();
+ reporter.main();
+ super_mixin.main();
+}
diff --git a/pkg/analyzer_cli/test/data/angular_options.yaml b/pkg/analyzer_cli/test/data/angular_options.yaml
new file mode 100644
index 0000000..e17c22a
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/angular_options.yaml
@@ -0,0 +1,7 @@
+analyzer:
+ plugins:
+ angular2_analyzer_plugin:
+ path: /Users/pquitslund/src/git/clones/angular2-dart-analyzer/analyzer_plugin/
+ class_name: AngularAnalyzerPlugin
+ library_uri: package:angular2_analyzer_plugin/plugin.dart
+
\ No newline at end of file
diff --git a/pkg/analyzer_cli/test/data/bad_plugin_options.yaml b/pkg/analyzer_cli/test/data/bad_plugin_options.yaml
new file mode 100644
index 0000000..9a389b0
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/bad_plugin_options.yaml
@@ -0,0 +1,6 @@
+analyzer:
+ plugins:
+ - lists
+ - are
+ - not
+ - supported
diff --git a/pkg/analyzer_cli/test/data/empty_options.yaml b/pkg/analyzer_cli/test/data/empty_options.yaml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/empty_options.yaml
diff --git a/pkg/analyzer_cli/test/data/file_with_error.dart b/pkg/analyzer_cli/test/data/file_with_error.dart
new file mode 100644
index 0000000..6b4f997
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_error.dart
@@ -0,0 +1,3 @@
+
+error
+
diff --git a/pkg/analyzer_cli/test/data/file_with_hint.dart b/pkg/analyzer_cli/test/data/file_with_hint.dart
new file mode 100644
index 0000000..7c46754
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_hint.dart
@@ -0,0 +1,3 @@
+main() {
+ int unused;
+}
diff --git a/pkg/analyzer_cli/test/data/file_with_warning.dart b/pkg/analyzer_cli/test/data/file_with_warning.dart
new file mode 100644
index 0000000..6f21a74
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/file_with_warning.dart
@@ -0,0 +1,3 @@
+main() {
+ undefined();
+}
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/lib.dart b/pkg/analyzer_cli/test/data/library_and_parts/lib.dart
new file mode 100644
index 0000000..a1ff776
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/lib.dart
@@ -0,0 +1,3 @@
+library example;
+
+part 'part1.dart';
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/part1.dart b/pkg/analyzer_cli/test/data/library_and_parts/part1.dart
new file mode 100644
index 0000000..f2fe166
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/part1.dart
@@ -0,0 +1 @@
+part of example;
diff --git a/pkg/analyzer_cli/test/data/library_and_parts/part2.dart b/pkg/analyzer_cli/test/data/library_and_parts/part2.dart
new file mode 100644
index 0000000..47f4917
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/library_and_parts/part2.dart
@@ -0,0 +1 @@
+part of nothing;
diff --git a/pkg/analyzer_cli/test/data/linter_project/.analysis_options b/pkg/analyzer_cli/test/data/linter_project/.analysis_options
new file mode 100644
index 0000000..6af57a5
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/.analysis_options
@@ -0,0 +1,3 @@
+linter:
+ rules:
+ - camel_case_types
diff --git a/pkg/analyzer_cli/test/data/linter_project/test_file.dart b/pkg/analyzer_cli/test/data/linter_project/test_file.dart
new file mode 100644
index 0000000..c1726a8
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/linter_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.linter_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options b/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options
new file mode 100644
index 0000000..1bb8bf6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/.analysis_options
@@ -0,0 +1 @@
+# empty
diff --git a/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart b/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart
new file mode 100644
index 0000000..93088d6
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_lints_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.no_lints_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart b/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart
new file mode 100644
index 0000000..b346f7f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/no_packages_file/sdk_ext_user.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:foo';
+
+main() {
+ // import of 'dart:foo' should resolve to a file which defines bar().
+ bar();
+}
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options b/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options
new file mode 100644
index 0000000..ebd4e64
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/.analysis_options
@@ -0,0 +1,5 @@
+analyzer:
+ errors:
+ unused_local_variable: ignore
+ language:
+ enableSuperMixins: true
diff --git a/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart b/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart
new file mode 100644
index 0000000..e8f168b
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/options_tests_project/test_file.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.options_test_project.test_file;
+
+class a {}
diff --git a/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext
new file mode 100644
index 0000000..71160ea
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/_sdkext
@@ -0,0 +1,3 @@
+{
+ "dart:foo": "foo.dart"
+}
diff --git a/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart
new file mode 100644
index 0000000..c56eef9
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/package_with_sdk_extension/lib/foo.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void bar() {}
diff --git a/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart b/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart
new file mode 100644
index 0000000..b346f7f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/packages_file/sdk_ext_user.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:foo';
+
+main() {
+ // import of 'dart:foo' should resolve to a file which defines bar().
+ bar();
+}
diff --git a/pkg/analyzer_cli/test/data/plugin_options.yaml b/pkg/analyzer_cli/test/data/plugin_options.yaml
new file mode 100644
index 0000000..483e76f
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/plugin_options.yaml
@@ -0,0 +1,7 @@
+analyzer:
+ plugins:
+ my_plugin1:
+ version: any
+ library_uri: 'package:my_plugin/my_plugin.dart'
+ class_name: MyPlugin
+
\ No newline at end of file
diff --git a/pkg/analyzer_cli/test/data/strong_example.dart b/pkg/analyzer_cli/test/data/strong_example.dart
new file mode 100644
index 0000000..2f332cd
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/strong_example.dart
@@ -0,0 +1,18 @@
+// 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.
+
+/// This produces an error with --strong enabled, but not otherwise.
+class MyIterable extends Iterable<String> {
+ // Error: invalid override
+ Iterator<Object> get iterator => [1, 2, 3].iterator;
+}
+
+main() {
+ var i = new MyIterable().iterator..moveNext();
+ print(i.current);
+
+ // Error: type check failed
+ List<String> list = <dynamic>[1, 2, 3];
+ print(list);
+}
diff --git a/pkg/analyzer_cli/test/data/super_mixin_example.dart b/pkg/analyzer_cli/test/data/super_mixin_example.dart
new file mode 100644
index 0000000..ea90486
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/super_mixin_example.dart
@@ -0,0 +1,18 @@
+// 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.
+
+/// This produces errors normally, but --supermixin disables them.
+class Test extends Object with C {
+ void foo() {}
+}
+
+abstract class B {
+ void foo();
+}
+
+abstract class C extends B {
+ void bar() {
+ super.foo();
+ }
+}
diff --git a/pkg/analyzer_cli/test/data/test_file.dart b/pkg/analyzer_cli/test/data/test_file.dart
new file mode 100644
index 0000000..1ac3540
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/test_file.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.data.test_file;
diff --git a/pkg/analyzer_cli/test/data/test_options.yaml b/pkg/analyzer_cli/test/data/test_options.yaml
new file mode 100644
index 0000000..ae890ee
--- /dev/null
+++ b/pkg/analyzer_cli/test/data/test_options.yaml
@@ -0,0 +1,2 @@
+test_plugin:
+ foo: bar
diff --git a/pkg/analyzer_cli/test/driver_test.dart b/pkg/analyzer_cli/test/driver_test.dart
new file mode 100644
index 0000000..f313355
--- /dev/null
+++ b/pkg/analyzer_cli/test/driver_test.dart
@@ -0,0 +1,486 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.driver;
+
+import 'dart:io';
+
+import 'package:analyzer/plugin/options.dart';
+import 'package:analyzer/source/analysis_options_provider.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:analyzer_cli/src/bootloader.dart';
+import 'package:analyzer_cli/src/driver.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:path/path.dart' as path;
+import 'package:plugin/plugin.dart';
+import 'package:unittest/unittest.dart';
+import 'package:yaml/src/yaml_node.dart';
+
+// TODO(pq): fix tests to run safely on the bots
+// https://github.com/dart-lang/sdk/issues/25001
+main() {}
+_main() {
+ group('Driver', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ });
+
+ group('options', () {
+ test('custom processor', () {
+ Driver driver = new Driver();
+ TestProcessor processor = new TestProcessor();
+ driver.userDefinedPlugins = [new TestPlugin(processor)];
+ driver.start([
+ '--options',
+ 'test/data/test_options.yaml',
+ 'test/data/test_file.dart'
+ ]);
+ expect(processor.options['test_plugin'], isNotNull);
+ expect(processor.exception, isNull);
+ });
+ });
+
+ group('exit codes', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ ExitHandler savedExitHandler;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ savedExitHandler = exitHandler;
+ exitHandler = (code) => exitCode = code;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ exitHandler = savedExitHandler;
+ });
+
+ test('fatal hints', () {
+ drive('test/data/file_with_hint.dart', args: ['--fatal-hints']);
+ expect(exitCode, 3);
+ });
+
+ test('not fatal hints', () {
+ drive('test/data/file_with_hint.dart');
+ expect(exitCode, 0);
+ });
+
+ test('fatal errors', () {
+ drive('test/data/file_with_error.dart');
+ expect(exitCode, 3);
+ });
+
+ test('not fatal warnings', () {
+ drive('test/data/file_with_warning.dart');
+ expect(exitCode, 0);
+ });
+
+ test('fatal warnings', () {
+ drive('test/data/file_with_warning.dart', args: ['--fatal-warnings']);
+ expect(exitCode, 3);
+ });
+
+ test('missing options file', () {
+ drive('test/data/test_file.dart', options: 'test/data/NO_OPTIONS_HERE');
+ expect(exitCode, 3);
+ });
+
+ test('missing dart file', () {
+ drive('test/data/NO_DART_FILE_HERE.dart');
+ expect(exitCode, 3);
+ });
+
+ test('part file', () {
+ drive('test/data/library_and_parts/part2.dart');
+ expect(exitCode, 3);
+ });
+
+ test('non-dangling part file', () {
+ Driver driver = new Driver();
+ driver.start([
+ 'test/data/library_and_parts/lib.dart',
+ 'test/data/library_and_parts/part1.dart',
+ ]);
+ expect(exitCode, 0);
+ });
+
+ test('extra part file', () {
+ Driver driver = new Driver();
+ driver.start([
+ 'test/data/library_and_parts/lib.dart',
+ 'test/data/library_and_parts/part1.dart',
+ 'test/data/library_and_parts/part2.dart',
+ ]);
+ expect(exitCode, 3);
+ });
+ });
+
+ group('linter', () {
+ group('lints in options', () {
+ StringSink savedOutSink;
+ Driver driver;
+
+ setUp(() {
+ savedOutSink = outSink;
+ outSink = new StringBuffer();
+
+ driver = new Driver();
+ driver.start([
+ '--options',
+ 'test/data/linter_project/.analysis_options',
+ '--lints',
+ 'test/data/linter_project/test_file.dart'
+ ]);
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ });
+
+ test('gets analysis options', () {
+ /// Lints should be enabled.
+ expect(driver.context.analysisOptions.lint, isTrue);
+
+ /// The .analysis_options file only specifies 'camel_case_types'.
+ var lintNames = getLints(driver.context).map((r) => r.name);
+ expect(lintNames, orderedEquals(['camel_case_types']));
+ });
+
+ test('generates lints', () {
+ expect(outSink.toString(),
+ contains('[lint] Name types using UpperCamelCase.'));
+ });
+ });
+
+ group('default lints', () {
+ StringSink savedOutSink;
+ Driver driver;
+
+ setUp(() {
+ savedOutSink = outSink;
+ outSink = new StringBuffer();
+
+ driver = new Driver();
+ driver.start([
+ '--lints',
+ 'test/data/linter_project/test_file.dart',
+ '--options',
+ 'test/data/linter_project/.analysis_options'
+ ]);
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ });
+
+ test('gets default lints', () {
+ /// Lints should be enabled.
+ expect(driver.context.analysisOptions.lint, isTrue);
+
+ /// Default list should include camel_case_types.
+ var lintNames = getLints(driver.context).map((r) => r.name);
+ expect(lintNames, contains('camel_case_types'));
+ });
+
+ test('generates lints', () {
+ expect(outSink.toString(),
+ contains('[lint] Name types using UpperCamelCase.'));
+ });
+ });
+
+ group('no `--lints` flag (none in options)', () {
+ StringSink savedOutSink;
+ Driver driver;
+
+ setUp(() {
+ savedOutSink = outSink;
+ outSink = new StringBuffer();
+
+ driver = new Driver();
+ driver.start([
+ 'test/data/no_lints_project/test_file.dart',
+ '--options',
+ 'test/data/no_lints_project/.analysis_options'
+ ]);
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ });
+
+ test('lints disabled', () {
+ expect(driver.context.analysisOptions.lint, isFalse);
+ });
+
+ test('no registered lints', () {
+ expect(getLints(driver.context), isEmpty);
+ });
+
+ test('no generated warnings', () {
+ expect(outSink.toString(), contains('No issues found'));
+ });
+ });
+ });
+
+ test('containsLintRuleEntry', () {
+ Map<String, YamlNode> options;
+ options = parseOptions('''
+linter:
+ rules:
+ - foo
+ ''');
+ expect(containsLintRuleEntry(options), true);
+ options = parseOptions('''
+ ''');
+ expect(containsLintRuleEntry(options), false);
+ options = parseOptions('''
+linter:
+ rules:
+ # - foo
+ ''');
+ expect(containsLintRuleEntry(options), true);
+ options = parseOptions('''
+linter:
+ # rules:
+ # - foo
+ ''');
+ expect(containsLintRuleEntry(options), false);
+ });
+
+ group('options processing', () {
+ group('error filters', () {
+ StringSink savedOutSink;
+ Driver driver;
+
+ setUp(() {
+ savedOutSink = outSink;
+ outSink = new StringBuffer();
+
+ driver = new Driver();
+ driver.start([
+ 'test/data/options_tests_project/test_file.dart',
+ '--options',
+ 'test/data/options_tests_project/.analysis_options'
+ ]);
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ });
+
+ test('filters', () {
+ var filters =
+ driver.context.getConfigurationData(CONFIGURED_ERROR_FILTERS);
+ expect(filters, hasLength(1));
+
+ var unused_error = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+ ['x']
+ ]);
+ expect(filters.any((filter) => filter(unused_error)), isTrue);
+ });
+
+ test('language config', () {
+ expect(driver.context.analysisOptions.enableSuperMixins, isTrue);
+ });
+ });
+ });
+
+ group('in temp directory', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ Directory savedCurrentDirectory;
+ Directory tempDir;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ savedCurrentDirectory = Directory.current;
+ tempDir = Directory.systemTemp.createTempSync('analyzer_');
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ Directory.current = savedCurrentDirectory;
+ tempDir.deleteSync(recursive: true);
+ });
+
+ test('packages folder', () {
+ Directory.current = tempDir;
+ new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync('''
+import 'package:foo/bar.dart';
+main() {
+ baz();
+}
+ ''');
+ Directory packagesDir =
+ new Directory(path.join(tempDir.path, 'packages'));
+ packagesDir.createSync();
+ Directory fooDir = new Directory(path.join(packagesDir.path, 'foo'));
+ fooDir.createSync();
+ new File(path.join(fooDir.path, 'bar.dart')).writeAsStringSync('''
+void baz() {}
+ ''');
+ new Driver().start(['test.dart']);
+ expect(exitCode, 0);
+ });
+
+ test('no package resolution', () {
+ Directory.current = tempDir;
+ new File(path.join(tempDir.path, 'test.dart')).writeAsStringSync('''
+import 'package:path/path.dart';
+main() {}
+ ''');
+ new Driver().start(['test.dart']);
+ expect(exitCode, 3);
+ String stdout = outSink.toString();
+ expect(stdout, contains('[error] Target of URI does not exist'));
+ expect(stdout, contains('1 error found.'));
+ expect(errorSink.toString(), '');
+ });
+
+ test('bad package root', () {
+ new Driver().start(['--package-root', 'does/not/exist', 'test.dart']);
+ String stdout = outSink.toString();
+ expect(exitCode, 3);
+ expect(
+ stdout,
+ contains(
+ 'Package root directory (does/not/exist) does not exist.'));
+ });
+ });
+ });
+ group('Bootloader', () {
+ group('plugin processing', () {
+ StringSink savedErrorSink;
+ setUp(() {
+ savedErrorSink = errorSink;
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ errorSink = savedErrorSink;
+ });
+ test('bad format', () {
+ BootLoader loader = new BootLoader();
+ loader.createImage([
+ '--options',
+ 'test/data/bad_plugin_options.yaml',
+ 'test/data/test_file.dart'
+ ]);
+ expect(
+ errorSink.toString(),
+ equals('Plugin configuration skipped: Unrecognized plugin config '
+ 'format, expected `YamlMap`, got `YamlList` '
+ '(line 2, column 4)\n'));
+ });
+ test('plugin config', () {
+ BootLoader loader = new BootLoader();
+ Image image = loader.createImage([
+ '--options',
+ 'test/data/plugin_options.yaml',
+ 'test/data/test_file.dart'
+ ]);
+ var plugins = image.config.plugins;
+ expect(plugins, hasLength(1));
+ expect(plugins.first.name, equals('my_plugin1'));
+ });
+ group('plugin validation', () {
+ test('requires class name', () {
+ expect(
+ validate(new PluginInfo(
+ name: 'test_plugin', libraryUri: 'my_package/foo.dart')),
+ isNotNull);
+ });
+ test('requires library URI', () {
+ expect(
+ validate(
+ new PluginInfo(name: 'test_plugin', className: 'MyPlugin')),
+ isNotNull);
+ });
+ test('check', () {
+ expect(
+ validate(new PluginInfo(
+ name: 'test_plugin',
+ className: 'MyPlugin',
+ libraryUri: 'my_package/foo.dart')),
+ isNull);
+ });
+ });
+ });
+ });
+}
+
+const emptyOptionsFile = 'test/data/empty_options.yaml';
+
+/// Start a driver for the given [source], optionally providing additional
+/// [args] and an [options] file path. The value of [options] defaults to
+/// an empty options file to avoid unwanted configuration from an otherwise
+/// discovered options file.
+void drive(String source,
+ {String options: emptyOptionsFile,
+ List<String> args: const <String>[]}) =>
+ new Driver().start(['--options', options, source]..addAll(args));
+
+Map<String, YamlNode> parseOptions(String src) =>
+ new AnalysisOptionsProvider().getOptionsFromString(src);
+
+class TestPlugin extends Plugin {
+ TestProcessor processor;
+ TestPlugin(this.processor);
+
+ @override
+ String get uniqueIdentifier => 'test_plugin.core';
+
+ @override
+ void registerExtensionPoints(RegisterExtensionPoint register) {
+ // None
+ }
+
+ @override
+ void registerExtensions(RegisterExtension register) {
+ register(OPTIONS_PROCESSOR_EXTENSION_POINT_ID, processor);
+ }
+}
+
+class TestProcessor extends OptionsProcessor {
+ Map<String, YamlNode> options;
+ Exception exception;
+
+ @override
+ void onError(Exception exception) {
+ this.exception = exception;
+ }
+
+ @override
+ void optionsProcessed(
+ AnalysisContext context, Map<String, YamlNode> options) {
+ this.options = options;
+ }
+}
+
+class TestSource implements Source {
+ TestSource();
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer_cli/test/error_test.dart b/pkg/analyzer_cli/test/error_test.dart
new file mode 100644
index 0000000..ad80133
--- /dev/null
+++ b/pkg/analyzer_cli/test/error_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+library analyzer_cli.test.error;
+
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+void main() {
+ group('error', () {
+ test("a valid Dart file doesn't throw any errors", () {
+ expect(errorsForFile('void main() => print("Hello, world!");'), isNull);
+ });
+
+ test("an empty Dart file doesn't throw any errors", () {
+ expect(errorsForFile(''), isNull);
+ });
+
+ test("an error on the first line", () {
+ expect(errorsForFile('void foo;\n'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+
+ test("an error on the last line", () {
+ expect(errorsForFile('\nvoid foo;'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+
+ test("an error in the middle", () {
+ expect(errorsForFile('\nvoid foo;\n'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+
+ var veryLongString = new List.filled(107, ' ').join('');
+
+ test("an error at the end of a very long line", () {
+ expect(errorsForFile('$veryLongString void foo;'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+
+ test("an error at the beginning of a very long line", () {
+ expect(errorsForFile('void foo; $veryLongString'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+
+ test("an error in the middle of a very long line", () {
+ expect(errorsForFile('$veryLongString void foo;$veryLongString'), equals(
+ "Error in test.dart: Variables cannot have a type of 'void'\n"));
+ });
+ });
+}
diff --git a/pkg/analyzer_cli/test/mocks.dart b/pkg/analyzer_cli/test/mocks.dart
new file mode 100644
index 0000000..794521c
--- /dev/null
+++ b/pkg/analyzer_cli/test/mocks.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.mocks;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer_cli/src/options.dart';
+import 'package:typed_mock/typed_mock.dart';
+
+class MockAnalysisError extends TypedMock implements AnalysisError {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockAnalysisErrorInfo extends TypedMock implements AnalysisErrorInfo {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockCommandLineOptions extends TypedMock implements CommandLineOptions {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockErrorCode extends TypedMock implements ErrorCode {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockErrorType extends TypedMock implements ErrorType {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockLineInfo extends TypedMock implements LineInfo {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockLineInfo_Location extends TypedMock implements LineInfo_Location {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class MockSource extends TypedMock implements Source {
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analyzer_cli/test/options_test.dart b/pkg/analyzer_cli/test/options_test.dart
new file mode 100644
index 0000000..900747b
--- /dev/null
+++ b/pkg/analyzer_cli/test/options_test.dart
@@ -0,0 +1,190 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.options;
+
+import 'package:analyzer_cli/src/options.dart';
+import 'package:args/args.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+ group('CommandLineOptions', () {
+ group('parse', () {
+ test('defaults', () {
+ CommandLineOptions options =
+ CommandLineOptions.parse(['--dart-sdk', '.', 'foo.dart']);
+ expect(options, isNotNull);
+ expect(options.dartSdkPath, isNotNull);
+ expect(options.disableHints, isFalse);
+ expect(options.lints, isFalse);
+ expect(options.displayVersion, isFalse);
+ expect(options.enableStrictCallChecks, isFalse);
+ expect(options.enableSuperMixins, isFalse);
+ expect(options.enableTypeChecks, isFalse);
+ expect(options.hintsAreFatal, isFalse);
+ expect(options.ignoreUnrecognizedFlags, isFalse);
+ expect(options.log, isFalse);
+ expect(options.machineFormat, isFalse);
+ expect(options.packageRootPath, isNull);
+ expect(options.shouldBatch, isFalse);
+ expect(options.showPackageWarnings, isFalse);
+ expect(options.showSdkWarnings, isFalse);
+ expect(options.sourceFiles, equals(['foo.dart']));
+ expect(options.warningsAreFatal, isFalse);
+ expect(options.strongMode, isFalse);
+ });
+
+ test('batch', () {
+ CommandLineOptions options =
+ CommandLineOptions.parse(['--dart-sdk', '.', '--batch']);
+ expect(options.shouldBatch, isTrue);
+ });
+
+ test('defined variables', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '-Dfoo=bar', 'foo.dart']);
+ expect(options.definedVariables['foo'], equals('bar'));
+ expect(options.definedVariables['bar'], isNull);
+ });
+
+ test('enable strict call checks', () {
+ CommandLineOptions options = CommandLineOptions.parse(
+ ['--dart-sdk', '.', '--enable-strict-call-checks', 'foo.dart']);
+ expect(options.enableStrictCallChecks, isTrue);
+ });
+
+ test('enable super mixins', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--supermixin', 'foo.dart']);
+ expect(options.enableSuperMixins, isTrue);
+ });
+
+ test('enable type checks', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--enable_type_checks', 'foo.dart']);
+ expect(options.enableTypeChecks, isTrue);
+ });
+
+ test('hintsAreFatal', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--fatal-hints', 'foo.dart']);
+ expect(options.hintsAreFatal, isTrue);
+ });
+
+ test('log', () {
+ CommandLineOptions options =
+ CommandLineOptions.parse(['--dart-sdk', '.', '--log', 'foo.dart']);
+ expect(options.log, isTrue);
+ });
+
+ test('machine format', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--format=machine', 'foo.dart']);
+ expect(options.machineFormat, isTrue);
+ });
+
+ test('no-hints', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--no-hints', 'foo.dart']);
+ expect(options.disableHints, isTrue);
+ });
+
+ test('options', () {
+ CommandLineOptions options = CommandLineOptions.parse(
+ ['--dart-sdk', '.', '--options', 'options.yaml', 'foo.dart']);
+ expect(options.analysisOptionsFile, equals('options.yaml'));
+ });
+
+ test('lints', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--lints', 'foo.dart']);
+ expect(options.lints, isTrue);
+ });
+
+ test('package root', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '-p', 'bar', 'foo.dart']);
+ expect(options.packageRootPath, equals('bar'));
+ });
+
+ test('package warnings', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--package-warnings', 'foo.dart']);
+ expect(options.showPackageWarnings, isTrue);
+ });
+
+ test('sdk warnings', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--warnings', 'foo.dart']);
+ expect(options.showSdkWarnings, isTrue);
+ });
+
+ test('sourceFiles', () {
+ CommandLineOptions options = CommandLineOptions.parse(
+ ['--dart-sdk', '.', '--log', 'foo.dart', 'foo2.dart', 'foo3.dart']);
+ expect(options.sourceFiles,
+ equals(['foo.dart', 'foo2.dart', 'foo3.dart']));
+ });
+
+ test('warningsAreFatal', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--dart-sdk', '.', '--fatal-warnings', 'foo.dart']);
+ expect(options.warningsAreFatal, isTrue);
+ });
+
+ test('notice unrecognized flags', () {
+ expect(
+ () => new CommandLineParser()
+ .parse(['--bar', '--baz', 'foo.dart'], {}),
+ throwsA(new isInstanceOf<FormatException>()));
+ });
+
+ test('ignore unrecognized flags', () {
+ CommandLineOptions options = CommandLineOptions.parse([
+ '--ignore-unrecognized-flags',
+ '--bar',
+ '--baz',
+ '--dart-sdk',
+ '.',
+ 'foo.dart'
+ ]);
+ expect(options, isNotNull);
+ expect(options.sourceFiles, equals(['foo.dart']));
+ });
+
+ test('ignore unrecognized options', () {
+ CommandLineParser parser =
+ new CommandLineParser(alwaysIgnoreUnrecognized: true);
+ parser.addOption('optionA');
+ parser.addFlag('flagA');
+ ArgResults argResults =
+ parser.parse(['--optionA=1', '--optionB=2', '--flagA'], {});
+ expect(argResults['optionA'], '1');
+ expect(argResults['flagA'], isTrue);
+ });
+
+ test('strong mode', () {
+ CommandLineOptions options = CommandLineOptions
+ .parse(['--strong', 'foo.dart']);
+ expect(options.strongMode, isTrue);
+ });
+
+ test("can't specify package and package-root", () {
+ var failureMessage;
+ CommandLineOptions.parse(
+ ['--package-root', '.', '--packages', '.', 'foo.dart'],
+ (msg) => failureMessage = msg);
+ expect(failureMessage,
+ equals("Cannot specify both '--package-root' and '--packages."));
+ });
+
+ test("bad SDK dir", () {
+ var failureMessage;
+ CommandLineOptions.parse(
+ ['--dart-sdk', '&&&&&', 'foo.dart'], (msg) => failureMessage = msg);
+ expect(failureMessage, equals('Invalid Dart SDK path: &&&&&'));
+ });
+ });
+ });
+}
diff --git a/pkg/analyzer_cli/test/plugin_manager_test.dart b/pkg/analyzer_cli/test/plugin_manager_test.dart
new file mode 100644
index 0000000..16280b2
--- /dev/null
+++ b/pkg/analyzer_cli/test/plugin_manager_test.dart
@@ -0,0 +1,93 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.plugin_manager_test;
+
+import 'package:analyzer/src/plugin/plugin_configuration.dart';
+import 'package:analyzer_cli/src/plugin/plugin_manager.dart';
+import 'package:unittest/unittest.dart';
+
+main() {
+ group('plugin manager tests', () {
+ test('combine plugin info', () {
+ PluginInfo localInfo = new PluginInfo(name: 'my_plugin');
+ PluginInfo manifestInfo = new PluginInfo(
+ className: 'MyPlugin', libraryUri: 'my_plugin/my_plugin.dart');
+
+ PluginInfo merged = combine(localInfo, manifestInfo);
+ expect(merged.name, equals('my_plugin'));
+ expect(merged.className, equals('MyPlugin'));
+ expect(merged.libraryUri, equals('my_plugin/my_plugin.dart'));
+ });
+
+ test('find manifest', () {
+ const manifestSrc = '''
+library_uri: 'my_plugin/my_plugin.dart'
+''';
+ var packageMap = {'my_plugin': new Uri.file('my_plugin')};
+
+ PluginManager pm =
+ new PluginManager(packageMap, 'analyzer', (Uri uri) => manifestSrc);
+
+ PluginManifest manifest = pm.findManifest('my_plugin');
+ expect(manifest, isNotNull);
+ expect(manifest.plugin.libraryUri, equals('my_plugin/my_plugin.dart'));
+ });
+
+ final plugin1Uri = new Uri.file('my_plugin1');
+ final plugin2Uri = new Uri.file('my_plugin2');
+ final plugin3Uri = new Uri.file('my_plugin3');
+
+ const serverPluginManifest = '''
+library_uri: 'my_plugin2/my_plugin2.dart'
+contributes_to: analysis_server
+''';
+ const analyzerPluginManifest = '''
+library_uri: 'my_plugin3/my_plugin3.dart'
+contributes_to: analyzer
+''';
+
+ var packageMap = {
+ 'my_plugin': plugin1Uri,
+ 'my_plugin2': plugin2Uri,
+ 'my_plugin3': plugin3Uri
+ };
+
+ var manifestReader = (Uri uri) {
+ if (uri == plugin2Uri) return serverPluginManifest;
+ if (uri == plugin3Uri) return analyzerPluginManifest;
+ return null;
+ };
+
+ test('get plugin details', () {
+ PluginManager pm =
+ new PluginManager(packageMap, 'analysis_server', manifestReader);
+
+ PluginInfo notFound = new PluginInfo(name: 'my_plugin1');
+ PluginInfo applicable = new PluginInfo(name: 'my_plugin2');
+ PluginInfo notApplicable = new PluginInfo(name: 'my_plugin3');
+
+ PluginConfig localConfig =
+ new PluginConfig([notFound, applicable, notApplicable]);
+
+ Iterable<PluginDetails> details = pm.getPluginDetails(localConfig);
+ expect(details, hasLength(3));
+
+ List<PluginDetails> plugins = sortByName(details);
+
+ expect(plugins[0].plugin.name, equals('my_plugin1'));
+ expect(plugins[0].status, equals(PluginStatus.NotFound));
+ expect(plugins[1].plugin.name, equals('my_plugin2'));
+ expect(
+ plugins[1].plugin.libraryUri, equals('my_plugin2/my_plugin2.dart'));
+ expect(plugins[1].status, equals(PluginStatus.Applicable));
+ expect(plugins[2].plugin.name, equals('my_plugin3'));
+ expect(plugins[2].status, equals(PluginStatus.NotApplicable));
+ });
+ });
+}
+
+List<PluginDetails> sortByName(Iterable<PluginDetails> details) =>
+ details.toList()
+ ..sort((p1, p2) => p1.plugin.name.compareTo(p2.plugin.name));
diff --git a/pkg/analyzer_cli/test/reporter_test.dart b/pkg/analyzer_cli/test/reporter_test.dart
new file mode 100644
index 0000000..94b0896
--- /dev/null
+++ b/pkg/analyzer_cli/test/reporter_test.dart
@@ -0,0 +1,76 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.formatter;
+
+import 'package:analyzer/analyzer.dart';
+import 'package:analyzer_cli/src/error_formatter.dart';
+import 'package:typed_mock/typed_mock.dart';
+import 'package:unittest/unittest.dart' hide ErrorFormatter;
+
+import 'mocks.dart';
+
+main() {
+ group('reporter', () {
+ var out = new StringBuffer();
+
+ tearDown(() => out.clear());
+
+ // Options
+ var options = new MockCommandLineOptions();
+ when(options.enableTypeChecks).thenReturn(false);
+ when(options.hintsAreFatal).thenReturn(false);
+ when(options.machineFormat).thenReturn(false);
+
+ var reporter = new ErrorFormatter(out, options);
+
+ test('error', () {
+ var error = mockError(ErrorType.SYNTACTIC_ERROR, ErrorSeverity.ERROR);
+ reporter.formatErrors([error]);
+
+ expect(
+ out.toString(),
+ '''[error] MSG (/foo/bar/baz.dart, line 3, col 3)
+1 error found.
+''');
+ });
+
+ test('hint', () {
+ var error = mockError(ErrorType.HINT, ErrorSeverity.INFO);
+ reporter.formatErrors([error]);
+
+ expect(
+ out.toString(),
+ '''[hint] MSG (/foo/bar/baz.dart, line 3, col 3)
+1 hint found.
+''');
+ });
+ });
+}
+
+MockAnalysisErrorInfo mockError(ErrorType type, ErrorSeverity severity) {
+ // ErrorInfo
+ var info = new MockAnalysisErrorInfo();
+ var error = new MockAnalysisError();
+ var lineInfo = new MockLineInfo();
+ var location = new MockLineInfo_Location();
+ when(location.columnNumber).thenReturn(3);
+ when(location.lineNumber).thenReturn(3);
+ when(lineInfo.getLocation(anyObject)).thenReturn(location);
+ when(info.lineInfo).thenReturn(lineInfo);
+
+ // Details
+ var code = new MockErrorCode();
+ when(code.type).thenReturn(type);
+ when(code.errorSeverity).thenReturn(severity);
+ when(code.name).thenReturn('mock_code');
+ when(error.errorCode).thenReturn(code);
+ when(error.message).thenReturn('MSG');
+ var source = new MockSource();
+ when(source.fullName).thenReturn('/foo/bar/baz.dart');
+ when(error.source).thenReturn(source);
+ when(info.errors).thenReturn([error]);
+
+ return info;
+}
diff --git a/pkg/analyzer_cli/test/sdk_ext_test.dart b/pkg/analyzer_cli/test/sdk_ext_test.dart
new file mode 100644
index 0000000..6aa793d
--- /dev/null
+++ b/pkg/analyzer_cli/test/sdk_ext_test.dart
@@ -0,0 +1,57 @@
+// 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.
+
+
+/// Test that sdk extensions are properly detected in various scenarios.
+library analyzer_cli.test.sdk_ext;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+// TODO(pq): fix tests to run safely on the bots
+// https://github.com/dart-lang/sdk/issues/25001
+main() {}
+_main() {
+ group('Sdk extensions', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ Directory savedCurrentDirectory;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ savedCurrentDirectory = Directory.current;
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ Directory.current = savedCurrentDirectory;
+ });
+
+ test('--packages option supplied', () async {
+ var testDir = path.join(testDirectory, 'data', 'no_packages_file');
+ Directory.current = new Directory(testDir);
+ var packagesPath = path.join('..', 'packages_file', '.packages');
+ new Driver().start(['--packages', packagesPath, 'sdk_ext_user.dart']);
+
+ expect(exitCode, 0);
+ });
+
+ test('.packages file present', () async {
+ var testDir = path.join(testDirectory, 'data', 'packages_file');
+ Directory.current = new Directory(testDir);
+ new Driver().start(['sdk_ext_user.dart']);
+
+ expect(exitCode, 0);
+ });
+ });
+}
diff --git a/pkg/analyzer_cli/test/strong_mode_test.dart b/pkg/analyzer_cli/test/strong_mode_test.dart
new file mode 100644
index 0000000..763205a
--- /dev/null
+++ b/pkg/analyzer_cli/test/strong_mode_test.dart
@@ -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.
+
+library analyzer_cli.test.strong_mode;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'driver_test.dart';
+import 'utils.dart';
+
+/// End-to-end test for --strong checking.
+///
+/// Most strong mode tests are in Analyzer, but this verifies the option is
+/// working and producing extra errors as expected.
+///
+/// Generally we don't want a lot of cases here as it requires spinning up a
+/// full analysis context.
+///
+// TODO(pq): fix tests to run safely on the bots
+// https://github.com/dart-lang/sdk/issues/25001
+main () {}
+_main() {
+ group('--strong', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ });
+
+ test('produces stricter errors', () async {
+ var testPath = path.join(testDirectory, 'data/strong_example.dart');
+ new Driver().start(['--options', emptyOptionsFile, '--strong', testPath]);
+
+ expect(exitCode, 3);
+ var stdout = outSink.toString();
+ expect(stdout, contains('[error] Invalid override'));
+ expect(stdout, contains('[error] Type check failed'));
+ expect(stdout, contains('2 errors found.'));
+ expect(errorSink.toString(), '');
+ });
+ });
+}
diff --git a/pkg/analyzer_cli/test/super_mixin_test.dart b/pkg/analyzer_cli/test/super_mixin_test.dart
new file mode 100644
index 0000000..d2b7afe
--- /dev/null
+++ b/pkg/analyzer_cli/test/super_mixin_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analyzer_cli.test.super_mixin;
+
+import 'dart:io';
+
+import 'package:analyzer_cli/src/driver.dart' show Driver, errorSink, outSink;
+import 'package:path/path.dart' as path;
+import 'package:unittest/unittest.dart';
+
+import 'utils.dart';
+
+/// End-to-end test for --supermixins.
+///
+/// Most super mixin tests are in Analyzer, but this verifies the option is
+/// working and producing extra errors as expected.
+///
+/// Generally we don't want a lot of cases here as it requires spinning up a
+/// full analysis context.
+void main() {
+ group('--supermixins', () {
+ StringSink savedOutSink, savedErrorSink;
+ int savedExitCode;
+ setUp(() {
+ savedOutSink = outSink;
+ savedErrorSink = errorSink;
+ savedExitCode = exitCode;
+ outSink = new StringBuffer();
+ errorSink = new StringBuffer();
+ });
+ tearDown(() {
+ outSink = savedOutSink;
+ errorSink = savedErrorSink;
+ exitCode = savedExitCode;
+ });
+
+ test('produces errors when option absent', () async {
+ var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
+ new Driver().start([testPath]);
+
+ expect(exitCode, 3);
+ var stdout = outSink.toString();
+ expect(
+ stdout,
+ contains(
+ "[error] The class 'C' cannot be used as a mixin because it extends a class other than Object"));
+ expect(
+ stdout,
+ contains(
+ "[error] The class 'C' cannot be used as a mixin because it references 'super'"));
+ expect(stdout, contains('2 errors found.'));
+ expect(errorSink.toString(), '');
+ });
+
+ test('produces no errors when option present', () async {
+ var testPath = path.join(testDirectory, 'data/super_mixin_example.dart');
+ new Driver().start(['--supermixin', testPath]);
+
+ expect(exitCode, 0);
+ var stdout = outSink.toString();
+ expect(stdout, contains('No issues found'));
+ });
+ });
+}
diff --git a/pkg/analyzer_cli/test/utils.dart b/pkg/analyzer_cli/test/utils.dart
new file mode 100644
index 0000000..25779ab
--- /dev/null
+++ b/pkg/analyzer_cli/test/utils.dart
@@ -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.
+
+library analyzer_cli.test.utils;
+
+import 'dart:io';
+import 'dart:mirrors';
+
+import 'package:analyzer/analyzer.dart';
+import 'package:path/path.dart' as pathos;
+
+/// Returns the string representation of the [AnalyzerErrorGroup] thrown when
+/// parsing [contents] as a Dart file. If [contents] doesn't throw any errors,
+/// this will return null.
+///
+/// This replaces the filename in the error string with its basename, since the
+/// full path will vary from machine to machine. It also replaces the exception
+/// message with "..." to decouple these tests from the specific exception
+/// messages.
+String errorsForFile(String contents) {
+ return withTempDir((temp) {
+ var path = pathos.join(temp, 'test.dart');
+ new File(path).writeAsStringSync(contents);
+ try {
+ parseDartFile(path);
+ } on AnalyzerErrorGroup catch (e) {
+ return e.toString().replaceAllMapped(
+ new RegExp(r"^(Error on line \d+ of )((?:[A-Z]+:)?[^:]+): .*$",
+ multiLine: true),
+ (match) => match[1] + pathos.basename(match[2]) + ': ...');
+ }
+ return null;
+ });
+}
+
+/// Creates a temporary directory and passes its path to [fn]. Once [fn]
+/// completes, the temporary directory and all its contents will be deleted.
+///
+/// Returns the return value of [fn].
+dynamic withTempDir(fn(String path)) {
+ var tempDir = Directory.systemTemp.createTempSync('analyzer_').path;
+ try {
+ return fn(tempDir);
+ } finally {
+ new Directory(tempDir).deleteSync(recursive: true);
+ }
+}
+
+/// Gets the test directory in a way that works with
+/// package:test and package:unittest.
+/// See <https://github.com/dart-lang/test/issues/110> for more info.
+final String testDirectory = pathos.dirname(
+ pathos.fromUri((reflectClass(_TestUtils).owner as LibraryMirror).uri));
+
+class _TestUtils {}
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 3bd085f..556006a 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -83,6 +83,8 @@
hasOption(options, Flags.trustTypeAnnotations),
trustPrimitives:
hasOption(options, Flags.trustPrimitives),
+ trustJSInteropTypeAnnotations:
+ hasOption(options, Flags.trustJSInteropTypeAnnotations),
enableMinification: hasOption(options, Flags.minify),
useFrequencyNamer:
!hasOption(options, Flags.noFrequencyBasedMinification),
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 668cb28..03f274e 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -40,6 +40,8 @@
static const String testMode = '--test-mode';
static const String trustPrimitives = '--trust-primitives';
static const String trustTypeAnnotations = '--trust-type-annotations';
+ static const String trustJSInteropTypeAnnotations =
+ '--experimental-trust-js-interop-type-annotations';
static const String useContentSecurityPolicy = '--csp';
static const String useCpsIr = '--use-cps-ir';
static const String verbose = '--verbose';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index ff49bcc..d2fa5ec 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -60,6 +60,7 @@
import '../universe/call_structure.dart' show
CallStructure;
import '../universe/world_impact.dart' show
+ ImpactStrategy,
WorldImpact;
import 'codegen.dart' show
@@ -424,6 +425,13 @@
///
/// Returns null if there is none.
Uri resolvePatchUri(String libraryName, Uri plaformConfigUri);
+
+ /// Creates an impact strategy to use for compilation.
+ ImpactStrategy createImpactStrategy(
+ {bool supportDeferredLoad: true,
+ bool supportDumpInfo: true}) {
+ return const ImpactStrategy();
+ }
}
/// Interface for resolving calls to foreign functions.
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 37c9855..7e9b40f 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -28,7 +28,8 @@
TypeUse;
import '../universe/world_impact.dart' show
WorldImpact,
- WorldImpactBuilder;
+ WorldImpactBuilder,
+ WorldImpactVisitor;
import '../util/util.dart' show
Pair,
Setlet;
@@ -78,6 +79,12 @@
_CodegenImpact(this.registry);
+ void apply(WorldImpactVisitor visitor) {
+ staticUses.forEach(visitor.visitStaticUse);
+ dynamicUses.forEach(visitor.visitDynamicUse);
+ typeUses.forEach(visitor.visitTypeUse);
+ }
+
void registerCompileTimeConstant(ConstantValue constant) {
if (_compileTimeConstants == null) {
_compileTimeConstants = new Setlet<ConstantValue>();
@@ -262,8 +269,6 @@
if (world.isProcessed(element)) return const WorldImpact();
registry = new CodegenRegistry(compiler, element);
- var impact = compiler.codegen(this, world);
- compiler.dumpInfoTask.registerImpact(element, impact);
- return impact;
+ return compiler.codegen(this, world);
}
}
diff --git a/pkg/compiler/lib/src/common/names.dart b/pkg/compiler/lib/src/common/names.dart
index 657cc6f..79389f5 100644
--- a/pkg/compiler/lib/src/common/names.dart
+++ b/pkg/compiler/lib/src/common/names.dart
@@ -109,13 +109,16 @@
static final Selector length = new Selector.getter(Names.length);
+ static final Selector codeUnitAt =
+ new Selector.call(const PublicName('codeUnitAt'), CallStructure.ONE_ARG);
+
/// List of all the selectors held in static fields.
///
/// These objects are shared between different runs in batch-mode and must
/// thus remain in the [Selector.canonicalizedValues] map.
static final List<Selector> ALL = <Selector>[
cancel, current, iterator, moveNext, noSuchMethod_, toString_,
- hashCode_, compareTo, equals, length];
+ hashCode_, compareTo, equals, length, codeUnitAt];
}
/// [Uri]s commonly used.
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 727f3aa..e422ef8 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -186,8 +186,21 @@
DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
bool hasBeenResolved(Element element);
+
+ /// Returns the precomputed [WorldImpact] for [element].
WorldImpact getWorldImpact(Element element);
+
+ /// Computes the [WorldImpact] for [element].
WorldImpact computeWorldImpact(Element element);
+
+ /// Removes the [WorldImpact] for [element] from the resolution cache. Later
+ /// calls to [getWorldImpact] or [computeWorldImpact] returns an empty impact.
+ void uncacheWorldImpact(Element element);
+
+ /// Removes the [WorldImpact]s for all [Element]s in the resolution cache. ,
+ /// Later calls to [getWorldImpact] or [computeWorldImpact] returns an empty
+ /// impact.
+ void emptyCache();
}
// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 392b202..fa655c5 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -137,6 +137,7 @@
import 'universe/use.dart' show
StaticUse;
import 'universe/world_impact.dart' show
+ ImpactStrategy,
WorldImpact;
import 'util/util.dart' show
Link,
@@ -157,6 +158,8 @@
final CacheStrategy cacheStrategy;
+ ImpactStrategy impactStrategy = const ImpactStrategy();
+
/**
* Map from token to the first preceding comment token.
*/
@@ -192,6 +195,7 @@
final bool enableUserAssertions;
final bool trustTypeAnnotations;
final bool trustPrimitives;
+ final bool trustJSInteropTypeAnnotations;
final bool disableTypeInferenceFlag;
final Uri deferredMapUri;
final bool dumpInfo;
@@ -322,6 +326,7 @@
ClassElement symbolImplementationClass;
// Initialized when symbolImplementationClass has been resolved.
+ // TODO(johnniwinther): Move this to [BackendHelpers].
FunctionElement symbolValidatedConstructor;
// Initialized when mirrorsUsedClass has been resolved.
@@ -426,6 +431,7 @@
this.enableUserAssertions: false,
this.trustTypeAnnotations: false,
this.trustPrimitives: false,
+ this.trustJSInteropTypeAnnotations: false,
bool disableTypeInferenceFlag: false,
this.maxConcreteTypeSize: 5,
this.enableMinification: false,
@@ -975,6 +981,9 @@
// something to the resolution queue. So we cannot wait with
// this until after the resolution queue is processed.
deferredLoadTask.beforeResolution(this);
+ impactStrategy = backend.createImpactStrategy(
+ supportDeferredLoad: deferredLoadTask.isProgramSplit,
+ supportDumpInfo: dumpInfo);
phase = PHASE_RESOLVING;
if (analyzeAll) {
@@ -1130,6 +1139,9 @@
}
emptyQueue(world);
world.queueIsClosed = true;
+ // Notify the impact strategy impacts are no longer needed for this
+ // enqueuer.
+ impactStrategy.onImpactUsed(world.impactUse);
backend.onQueueClosed();
assert(compilationFailed || world.checkNoEnqueuedInvokedInstanceMethods());
}
@@ -2019,6 +2031,20 @@
}
@override
+ void uncacheWorldImpact(Element element) {
+ assert(invariant(element, _worldImpactCache[element] != null,
+ message: "WorldImpact not computed for $element."));
+ _worldImpactCache[element] = const WorldImpact();
+ }
+
+ @override
+ void emptyCache() {
+ for (Element element in _worldImpactCache.keys) {
+ _worldImpactCache[element] = const WorldImpact();
+ }
+ }
+
+ @override
bool hasBeenResolved(Element element) {
return _worldImpactCache.containsKey(element);
}
diff --git a/pkg/compiler/lib/src/constants/values.dart b/pkg/compiler/lib/src/constants/values.dart
index 24b6370..2a7c5c4 100644
--- a/pkg/compiler/lib/src/constants/values.dart
+++ b/pkg/compiler/lib/src/constants/values.dart
@@ -375,6 +375,9 @@
: this.primitiveValue = value,
this.hashCode = value.slowToString().hashCode;
+ StringConstantValue.fromString(String value)
+ : this(new DartString.literal(value));
+
bool get isString => true;
DartType getType(CoreTypes types) => types.stringType;
@@ -748,4 +751,4 @@
@override
String unparse() => '>>non-constant<<';
-}
\ No newline at end of file
+}
diff --git a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
index 28dbd62..a227794 100644
--- a/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
+++ b/pkg/compiler/lib/src/cps_ir/bounds_checker.dart
@@ -168,6 +168,16 @@
applyConstraint(v2, v1.negated, -1);
}
+ void makeLessThanOrEqualToConstant(SignedVariable v1, int k) {
+ // v1 + v1 <= 2k
+ applyConstraint(v1, v1, 2 * k);
+ }
+
+ void makeGreaterThanOrEqualToConstant(SignedVariable v1, int k) {
+ // -v1 - v1 <= -2k
+ applyConstraint(v1.negated, v1.negated, -2 * k);
+ }
+
void makeConstant(SignedVariable v1, int k) {
// We model this using the constraints:
// v1 + v1 <= 2k
@@ -329,56 +339,130 @@
@override
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- if (node.operator != BuiltinOperator.NumAdd &&
- node.operator != BuiltinOperator.NumSubtract) {
- return;
+ if (!isInt(node)) return;
+ if (node.arguments.length == 1) {
+ applyUnaryOperator(node);
+ } else if (node.arguments.length == 2) {
+ applyBinaryOperator(node);
}
- if (!isInt(node.arguments[0].definition) ||
- !isInt(node.arguments[1].definition)) {
- return;
- }
- if (!isInt(node)) {
- // TODO(asgerf): The result of this operation should always be an integer,
- // but currently type propagation does not always prove this.
- return;
- }
- // We have `v1 = v2 +/- v3`, but the octagon cannot represent constraints
- // involving more than two variables. Check if one operand is a constant.
- int getConstantArgument(int n) {
- Primitive prim = node.arguments[n].definition;
- if (prim is Constant && prim.value.isInt) {
- IntConstantValue constant = prim.value;
- return constant.primitiveValue;
- }
- return null;
- }
- int constant = getConstantArgument(0);
- int operandIndex = 1;
- if (constant == null) {
- constant = getConstantArgument(1);
- operandIndex = 0;
- }
- if (constant == null) {
- // Neither argument was a constant.
- // Classical octagon-based analyzers would compute upper and lower bounds
- // for the two operands and add constraints for the result based on
- // those. For performance reasons we omit that.
- // TODO(asgerf): It seems expensive, but we should evaluate it.
- return;
- }
- SignedVariable v1 = getValue(node);
- SignedVariable v2 = getValue(node.arguments[operandIndex].definition);
+ }
- if (node.operator == BuiltinOperator.NumAdd) {
- // v1 = v2 + const
- makeFloatingPointSum(v1, v2, constant);
- } else if (operandIndex == 0) {
- // v1 = v2 - const
- makeFloatingPointSum(v1, v2, -constant);
- } else {
- // v1 = const - v2 <==> v1 = (-v2) + const
- makeFloatingPointSum(v1, v2.negated, constant);
+ void applyBinaryOperator(ApplyBuiltinOperator node) {
+ Primitive left = node.arguments[0].definition;
+ Primitive right = node.arguments[1].definition;
+ if (!isInt(left) || !isInt(right)) {
+ return;
}
+ SignedVariable leftVar = getValue(left);
+ SignedVariable rightVar = getValue(right);
+ SignedVariable result = getValue(node);
+ switch (node.operator) {
+ case BuiltinOperator.NumAdd:
+ int leftConst = getIntConstant(left);
+ if (leftConst != null) {
+ makeFloatingPointSum(result, rightVar, leftConst);
+ }
+ int rightConst = getIntConstant(right);
+ if (rightConst != null) {
+ makeFloatingPointSum(result, leftVar, rightConst);
+ }
+ // Attempt to compute the sign of the result.
+ // TODO(asgerf): Compute upper/lower bounds instead of using 0.
+ if (testConstraint(leftVar, rightVar, 0)) {
+ makeLessThanOrEqualToConstant(result, 0);
+ }
+ if (testConstraint(leftVar.negated, rightVar.negated, 0)) {
+ makeGreaterThanOrEqualToConstant(result, 0);
+ }
+ // Classical octagon-based analyzers would compute upper and lower
+ // bounds for the two operands and add constraints for the result based
+ // on those. For performance reasons we only compute the sign
+ // TODO(asgerf): It seems expensive, but we should evaluate it.
+ break;
+
+ case BuiltinOperator.NumSubtract:
+ int leftConst = getIntConstant(left);
+ if (leftConst != null) {
+ // result = leftConst - right = (-right) + leftConst
+ makeFloatingPointSum(result, rightVar.negated, leftConst);
+ }
+ int rightConst = getIntConstant(right);
+ if (rightConst != null) {
+ // result = left - rightConst = left + (-rightConst)
+ makeFloatingPointSum(result, leftVar, -rightConst);
+ }
+ // Attempt to compute the sign of the result.
+ if (isDefinitelyGreaterThanOrEqualTo(leftVar, rightVar)) {
+ makeGreaterThanOrEqualToConstant(result, 0);
+ }
+ if (isDefinitelyLessThanOrEqualTo(leftVar, rightVar)) {
+ makeLessThanOrEqualToConstant(result, 0);
+ }
+ break;
+
+ case BuiltinOperator.NumTruncatingDivideToSigned32:
+ if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
+ // If we divide by a positive number, the result is closer to zero.
+ // If we divide by a negative number, the result is negative, and
+ // thus less than the original (non-negative) number.
+ // TODO(asgerf): The divisor is currently always positive, because
+ // type propagation checks that, but we could do better.
+ makeLessThanOrEqual(result, leftVar);
+ }
+ break;
+
+ case BuiltinOperator.NumShr:
+ if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0)) {
+ makeLessThanOrEqual(result, leftVar);
+ }
+ int shiftAmount = getIntConstant(right);
+ if (shiftAmount != null) {
+ // TODO(asgerf): Compute upper bound on [leftVar] and use that
+ // instead of MAX_UINT32.
+ makeLessThanOrEqualToConstant(result, MAX_UINT32 >> shiftAmount);
+ }
+ break;
+
+ case BuiltinOperator.NumRemainder:
+ // TODO(asgerf): This check overlaps with checks performed in a type
+ // propagation transformation, and we can do it more precisely here.
+ // Should we do the rewrite here?
+ if (isDefinitelyGreaterThanOrEqualToConstant(leftVar, 0) &&
+ isDefinitelyGreaterThanOrEqualToConstant(rightVar, 1)) {
+ makeLessThanOrEqual(result, leftVar);
+ makeLessThan(result, rightVar);
+ }
+ break;
+
+ case BuiltinOperator.NumAnd:
+ // We use the faster UInt32 check instead of constraint based checks
+ // here, because the common case is that one operand is a constant.
+ if (isUInt32(left)) {
+ makeLessThanOrEqual(result, leftVar);
+ }
+ if (isUInt32(right)) {
+ makeLessThanOrEqual(result, rightVar);
+ }
+ break;
+
+ default:
+ }
+ }
+
+ void applyUnaryOperator(ApplyBuiltinOperator node) {
+ Primitive argument = node.arguments[0].definition;
+ if (!isInt(argument)) return;
+ if (node.operator == BuiltinOperator.NumNegate) {
+ valueOf[node] = getValue(argument).negated;
+ }
+ }
+
+ int getIntConstant(Primitive prim) {
+ if (prim is Constant && prim.value.isInt) {
+ IntConstantValue constant = prim.value;
+ return constant.primitiveValue;
+ }
+ return null;
}
@override
@@ -398,7 +482,7 @@
Monotonicity mono = monotonicity[param];
if (mono == null) {
// Value never changes. This is extremely uncommon.
- initialValue.substituteFor(param);
+ param.replaceUsesWith(initialValue);
} else if (mono == Monotonicity.Increasing) {
makeGreaterThanOrEqual(getValue(param), initialVariable);
} else if (mono == Monotonicity.Decreasing) {
@@ -468,7 +552,7 @@
}
}
- // ---------------- CALL EXPRESSIONS --------------------
+ // ---------------- PRIMITIVES --------------------
@override
void visitInvokeMethod(InvokeMethod node) {
@@ -478,7 +562,6 @@
.changesIndex()) {
currentEffectNumber = makeNewEffect();
}
- push(node.continuation.definition);
}
@override
@@ -486,7 +569,6 @@
if (world.getSideEffectsOfElement(node.target).changesIndex()) {
currentEffectNumber = makeNewEffect();
}
- push(node.continuation.definition);
}
@override
@@ -499,7 +581,6 @@
if (world.getSideEffectsOfElement(target).changesIndex()) {
currentEffectNumber = makeNewEffect();
}
- push(node.continuation.definition);
}
@override
@@ -507,19 +588,16 @@
if (world.getSideEffectsOfElement(node.target).changesIndex()) {
currentEffectNumber = makeNewEffect();
}
- push(node.continuation.definition);
}
@override
void visitTypeCast(TypeCast node) {
- push(node.continuation.definition);
}
@override
void visitGetLazyStatic(GetLazyStatic node) {
// TODO(asgerf): How do we get the side effects of a lazy field initializer?
currentEffectNumber = makeNewEffect();
- push(node.continuation.definition);
}
@override
@@ -527,23 +605,18 @@
if (node.nativeBehavior.sideEffects.changesIndex()) {
currentEffectNumber = makeNewEffect();
}
- push(node.continuation.definition);
}
@override
void visitAwait(Await node) {
currentEffectNumber = makeNewEffect();
- push(node.continuation.definition);
}
@override
void visitYield(Yield node) {
currentEffectNumber = makeNewEffect();
- push(node.continuation.definition);
}
- // ---------------- PRIMITIVES --------------------
-
@override
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
Primitive receiver = node.receiver.definition;
diff --git a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
index 9c1d83e..699e755 100644
--- a/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
+++ b/pkg/compiler/lib/src/cps_ir/builtin_operator.dart
@@ -70,6 +70,12 @@
/// Returns the empty string if no arguments are given.
StringConcatenate,
+ /// Corresponds to `a.charCodeAt(b)`. `a' must be a String. The index `b` must
+ /// be in range `0 <= b < a.length`.
+ /// TODO(sra): Consider replacing with a Primitive to allow lowering when 'a'
+ /// is nullable (i.e. throws).
+ CharCodeAt,
+
/// Returns true if the two arguments are the same value, and that value is
/// not NaN, or if one argument is +0 and the other is -0.
///
diff --git a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
index 7fc2ae3..ada5d1a 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_fragment.dart
@@ -123,35 +123,19 @@
return letPrim(apply);
}
- /// Inserts an invocation. binds its continuation, and returns the
- /// continuation parameter (i.e. the return value of the invocation).
- ///
- /// The continuation body becomes the new hole.
- Parameter invokeMethod(Primitive receiver,
+ /// Inserts an invocation and returns a primitive holding the returned value.
+ Primitive invokeMethod(Primitive receiver,
Selector selector,
TypeMask mask,
List<Primitive> arguments) {
- Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
- InvokeMethod invoke =
- new InvokeMethod(receiver, selector, mask, arguments, cont,
- sourceInformation);
- put(new LetCont(cont, invoke));
- context = cont;
- return cont.parameters.single;
+ return letPrim(new InvokeMethod(receiver, selector, mask, arguments,
+ sourceInformation));
}
- /// Inserts an invocation. binds its continuation, and returns the
- /// continuation parameter (i.e. the return value of the invocation).
- ///
- /// The continuation body becomes the new hole.
- Parameter invokeStatic(FunctionElement target, List<Primitive> arguments) {
- Continuation cont = new Continuation(<Parameter>[new Parameter(null)]);
- InvokeStatic invoke =
- new InvokeStatic(target, new Selector.fromElement(target), arguments,
- cont, sourceInformation);
- put(new LetCont(cont, invoke));
- context = cont;
- return cont.parameters.single;
+ /// Inserts an invocation and returns a primitive holding the returned value.
+ Primitive invokeStatic(FunctionElement target, List<Primitive> arguments) {
+ return letPrim(new InvokeStatic(target, new Selector.fromElement(target),
+ arguments, sourceInformation));
}
/// Inserts an invocation to a static function that throws an error.
@@ -253,10 +237,45 @@
Continuation letCont([List<Parameter> parameters]) {
if (parameters == null) parameters = <Parameter>[];
Continuation cont = new Continuation(parameters);
+ bindContinuation(cont);
+ return cont;
+ }
+
+ /// Binds an existing continuation at this position.
+ ///
+ /// The LetCont body becomes the new hole.
+ void bindContinuation(Continuation cont) {
LetCont let = new LetCont(cont, null);
put(let);
context = let;
- return cont;
+ }
+
+ /// Inlines [target] at the current position, substituting the provided
+ /// arguments.
+ ///
+ /// Returns a primitive containing the function's return value.
+ ///
+ /// The new hole is the the point after [target] has returned. The fragment
+ /// remains open, even if [target] never returns.
+ ///
+ /// The [target] function is destroyed and should not be reused.
+ Primitive inlineFunction(FunctionDefinition target,
+ Primitive thisArgument,
+ List<Primitive> arguments,
+ {Entity hint}) {
+ if (thisArgument != null) {
+ target.thisParameter.replaceUsesWith(thisArgument);
+ }
+ for (int i = 0; i < arguments.length; ++i) {
+ target.parameters[i].replaceUsesWith(arguments[i]);
+ }
+ Continuation returnCont = target.returnContinuation;
+ bindContinuation(returnCont);
+ put(target.body);
+ Parameter returnValue = returnCont.parameters.single;
+ returnValue.hint = hint;
+ context = returnCont;
+ return returnValue;
}
/// Returns a fragment whose context is the body of the given continuation.
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index b9f26d2..b75af81 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -668,9 +668,8 @@
assert(!element.isLocal);
assert(!element.isInstanceMember);
assert(isOpen);
- return _continueWithExpression(
- (k) => new ir.InvokeStatic(element, selector, arguments, k,
- sourceInformation));
+ return addPrimitive(
+ new ir.InvokeStatic(element, selector, arguments, sourceInformation));
}
ir.Primitive _buildInvokeSuper(Element target,
@@ -679,9 +678,8 @@
SourceInformation sourceInformation) {
assert(target.isInstanceMember);
assert(isOpen);
- return _continueWithExpression(
- (k) => new ir.InvokeMethodDirectly(
- buildThis(), target, selector, arguments, k, sourceInformation));
+ return addPrimitive(new ir.InvokeMethodDirectly(
+ buildThis(), target, selector, arguments, sourceInformation));
}
ir.Primitive _buildInvokeDynamic(ir.Primitive receiver,
@@ -690,9 +688,8 @@
List<ir.Primitive> arguments,
SourceInformation sourceInformation) {
assert(isOpen);
- return _continueWithExpression(
- (k) => new ir.InvokeMethod(receiver, selector, mask, arguments, k,
- sourceInformation));
+ return addPrimitive(new ir.InvokeMethod(
+ receiver, selector, mask, arguments, sourceInformation));
}
ir.Primitive _buildInvokeCall(ir.Primitive target,
@@ -1047,8 +1044,7 @@
/// initialized yet.
ir.Primitive buildStaticFieldLazyGet(FieldElement field,
SourceInformation sourceInformation) {
- return _continueWithExpression(
- (k) => new ir.GetLazyStatic(field, k, sourceInformation));
+ return addPrimitive(new ir.GetLazyStatic(field, sourceInformation));
}
/// Create a getter invocation of the static [getter].
@@ -1393,14 +1389,11 @@
// in expressionReceiver.iterator () iteratorInvoked
ir.Primitive expressionReceiver = buildExpression(this);
List<ir.Primitive> emptyArguments = <ir.Primitive>[];
- ir.Parameter iterator = new ir.Parameter(null);
- ir.Continuation iteratorInvoked = new ir.Continuation([iterator]);
- add(new ir.LetCont(iteratorInvoked,
+ ir.Primitive iterator = addPrimitive(
new ir.InvokeMethod(expressionReceiver,
Selectors.iterator,
iteratorMask,
- emptyArguments,
- iteratorInvoked)));
+ emptyArguments));
// Fill with:
// let cont loop(x, ...) =
@@ -1410,14 +1403,11 @@
// in loop(v, ...)
JumpCollector loop = new BackwardJumpCollector(environment, target: target);
addRecursiveContinuation(loop);
- ir.Parameter condition = new ir.Parameter(null);
- ir.Continuation moveNextInvoked = new ir.Continuation([condition]);
- add(new ir.LetCont(moveNextInvoked,
+ ir.Primitive condition = addPrimitive(
new ir.InvokeMethod(iterator,
Selectors.moveNext,
moveNextMask,
- emptyArguments,
- moveNextInvoked)));
+ emptyArguments));
// As a delimited term, build:
// <<BODY>> =
@@ -1432,14 +1422,12 @@
if (buildVariableDeclaration != null) {
buildVariableDeclaration(bodyBuilder);
}
- ir.Parameter currentValue = new ir.Parameter(null);
- ir.Continuation currentInvoked = new ir.Continuation([currentValue]);
- bodyBuilder.add(new ir.LetCont(currentInvoked,
+ ir.Primitive currentValue = bodyBuilder.addPrimitive(
new ir.InvokeMethod(
iterator,
Selectors.current,
currentMask,
- emptyArguments, currentInvoked)));
+ emptyArguments));
// TODO(sra): Does this cover all cases? The general setter case include
// super.
// TODO(johnniwinther): Extract this as a provided strategy.
@@ -2607,9 +2595,8 @@
assert(isOpen);
Selector selector =
new Selector.call(target.memberName, new CallStructure(arguments.length));
- return _continueWithExpression(
- (k) => new ir.InvokeMethodDirectly(
- receiver, target, selector, arguments, k, sourceInformation));
+ return addPrimitive(new ir.InvokeMethodDirectly(
+ receiver, target, selector, arguments, sourceInformation));
}
/// Loads parameters to a constructor body into the environment.
@@ -2654,10 +2641,9 @@
arguments = new List<ir.Primitive>.from(arguments)
..addAll(typeArguments);
}
- return _continueWithExpression(
- (k) => new ir.InvokeConstructor(
- type, element, selector, arguments, k, sourceInformation,
- allocationSiteType: allocationSiteType));
+ return addPrimitive(new ir.InvokeConstructor(
+ type, element, selector, arguments, sourceInformation,
+ allocationSiteType: allocationSiteType));
}
ir.Primitive buildTypeExpression(DartType type) {
@@ -2730,12 +2716,11 @@
{Element dependency}) {
assert(behavior != null);
TypeMask type = program.getTypeMaskForForeign(behavior);
- ir.Primitive result = _continueWithExpression((k) => new ir.ForeignCode(
+ ir.Primitive result = addPrimitive(new ir.ForeignCode(
codeTemplate,
type,
arguments,
behavior,
- k,
dependency: dependency));
if (!codeTemplate.isExpression) {
// Close the term if this is a "throw" expression or native body.
@@ -2792,8 +2777,7 @@
// `x as Object` and `x as dynamic` are the same as `x`.
return value;
}
- return _continueWithExpression(
- (k) => new ir.TypeCast(value, type, typeArguments, k));
+ return addPrimitive(new ir.TypeCast(value, type, typeArguments));
}
}
@@ -2836,14 +2820,12 @@
<ir.Primitive>[value]);
}
- ir.Node buildAwait(ir.Primitive value) {
- return _continueWithExpression((k) => new ir.Await(value, k));
+ ir.Primitive buildAwait(ir.Primitive value) {
+ return addPrimitive(new ir.Await(value));
}
void buildYield(ir.Primitive value, bool hasStar) {
- _continueWithExpression((k) {
- return new ir.Yield(value, hasStar, k);
- });
+ addPrimitive(new ir.Yield(value, hasStar));
}
ir.Primitive buildRefinement(ir.Primitive value, TypeMask type) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index c960bcb..829f942 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -3353,6 +3353,7 @@
ir.Primitive buildStaticFieldGet(FieldElement field, SourceInformation src) {
ConstantValue constant = getConstantForVariable(field);
if (constant != null && !field.isAssignable) {
+ typeMaskSystem.associateConstantValueWithElement(constant, field);
return irBuilder.buildConstant(constant, sourceInformation: src);
} else if (backend.constants.lazyStatics.contains(field)) {
return irBuilder.buildStaticFieldLazyGet(field, src);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
index dedfbad..a295902 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_integrity.dart
@@ -154,6 +154,9 @@
if (inScope[def] == ScopeType.NotInScope) {
error('Referenced out of scope: $def', ref);
}
+ if (ref.previous == ref) {
+ error('Shared Reference object to $def', ref);
+ }
if (ref.previous == null && def.firstRef != ref ||
ref.previous != null && ref.previous.next != ref) {
error('Broken .previous link in reference to $def', def);
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
index 50e84bd..53a1a98 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes.dart
@@ -123,12 +123,6 @@
}
}
-/// An expression that passes a continuation to a call.
-abstract class CallExpression extends Expression {
- Reference<Continuation> get continuation;
- Expression get next => continuation.definition.body;
-}
-
/// An expression without a continuation or a subexpression body.
///
/// These break straight-line control flow and can be thought of as ending a
@@ -149,19 +143,21 @@
bool get hasAtLeastOneUse => firstRef != null;
bool get hasMultipleUses => !hasAtMostOneUse;
- void substituteFor(Definition<T> other) {
- if (other == this) return;
- if (other.hasNoUses) return;
- Reference<T> previous, current = other.firstRef;
+ void replaceUsesWith(Definition<T> newDefinition) {
+ if (newDefinition == this) return;
+ if (hasNoUses) return;
+ Reference<T> previous, current = firstRef;
do {
- current.definition = this;
+ current.definition = newDefinition;
previous = current;
current = current.next;
} while (current != null);
- previous.next = firstRef;
- if (firstRef != null) firstRef.previous = previous;
- firstRef = other.firstRef;
- other.firstRef = null;
+ previous.next = newDefinition.firstRef;
+ if (newDefinition.firstRef != null) {
+ newDefinition.firstRef.previous = previous;
+ }
+ newDefinition.firstRef = firstRef;
+ firstRef = null;
}
}
@@ -220,6 +216,9 @@
}
}
+ /// True if this primitive has a value that can be used by other expressions.
+ bool get hasValue;
+
/// True if the primitive can be removed, assuming it has no uses
/// (this getter does not check if there are any uses).
///
@@ -268,6 +267,37 @@
assert(hasNoUses);
RemovalVisitor.remove(this);
}
+
+ /// Replaces this definition, both at the binding site and at all uses sites.
+ ///
+ /// This can be thought of as changing the definition of a `let` while
+ /// preserving the variable name:
+ ///
+ /// let x = OLD in BODY
+ /// ==>
+ /// let x = NEW in BODY
+ ///
+ void replaceWith(Primitive newDefinition) {
+ assert(this is! Parameter);
+ assert(newDefinition is! Parameter);
+ assert(newDefinition.parent == null);
+ replaceUsesWith(newDefinition);
+ destroy();
+ LetPrim let = parent;
+ let.primitive = newDefinition;
+ newDefinition.parent = let;
+ newDefinition.useElementAsHint(hint);
+ }
+}
+
+/// A primitive that is generally not safe for elimination, but may be marked
+/// as safe by type propagation
+//
+// TODO(asgerf): Store the flag in a bitmask in [Primitive] and get rid of this
+// class.
+abstract class UnsafePrimitive extends Primitive {
+ bool isSafeForElimination = false;
+ bool isSafeForReordering = false;
}
/// Operands to invocations and primitives are always variables. They point to
@@ -435,35 +465,49 @@
/// Discussion:
/// All information in the [selector] is technically redundant; it will likely
/// be removed.
-class InvokeStatic extends CallExpression {
+class InvokeStatic extends UnsafePrimitive {
final FunctionElement target;
final Selector selector;
final List<Reference<Primitive>> arguments;
- final Reference<Continuation> continuation;
final SourceInformation sourceInformation;
InvokeStatic(this.target,
this.selector,
List<Primitive> args,
- Continuation cont,
[this.sourceInformation])
- : arguments = _referenceList(args),
- continuation = new Reference<Continuation>(cont);
+ : arguments = _referenceList(args);
InvokeStatic.byReference(this.target,
this.selector,
this.arguments,
- this.continuation,
[this.sourceInformation]);
accept(Visitor visitor) => visitor.visitInvokeStatic(this);
+ bool get hasValue => true;
+
void setParentPointers() {
_setParentsOnList(arguments, this);
- continuation.parent = this;
}
}
+enum CallingConvention {
+ /// JS receiver is the Dart receiver, there are no extra arguments.
+ ///
+ /// For example: `foo.bar$1(x)`
+ Normal,
+
+ /// JS receiver is an interceptor, the first argument is the Dart receiver.
+ ///
+ /// For example: `getInterceptor(foo).bar$1(foo, x)`
+ Intercepted,
+
+ /// JS receiver is the Dart receiver, the first argument is a dummy value.
+ ///
+ /// For example: `foo.bar$1(0, x)`
+ DummyIntercepted,
+}
+
/// Invoke a method on an object.
///
/// This includes getters, setters, operators, and index getter/setters.
@@ -473,24 +517,30 @@
///
/// The [selector] records the names of named arguments. The value of named
/// arguments occur at the end of the [arguments] list, in normalized order.
-class InvokeMethod extends CallExpression {
+class InvokeMethod extends UnsafePrimitive {
Reference<Primitive> receiver;
Selector selector;
TypeMask mask;
final List<Reference<Primitive>> arguments;
- final Reference<Continuation> continuation;
final SourceInformation sourceInformation;
- /// If true, the [receiver] is intercepted and the actual receiver is in
- /// the first argument. Otherwise, the [receiver] is the actual receiver.
- ///
- /// This flag is always false for non-intercepted selectors, but it may also
- /// be false for intercepted selectors after dummy receiver optimization
- /// (in this case the first argument is a dummy value).
- ///
- /// It is always false before the unsugaring pass, where interceptors have
- /// not yet been introduced.
- bool receiverIsIntercepted = false;
+ CallingConvention callingConvention = CallingConvention.Normal;
+
+ Reference<Primitive> get dartReceiverReference {
+ return callingConvention == CallingConvention.Intercepted
+ ? arguments[0]
+ : receiver;
+ }
+
+ Primitive get dartReceiver => dartReceiverReference.definition;
+
+ Reference<Primitive> dartArgumentReference(int n) {
+ return callingConvention == CallingConvention.Normal
+ ? arguments[n]
+ : arguments[n + 1];
+ }
+
+ Primitive dartArgument(int n) => dartArgumentReference(n).definition;
/// If true, it is known that the receiver cannot be `null`.
bool receiverIsNotNull = false;
@@ -499,25 +549,23 @@
this.selector,
this.mask,
List<Primitive> arguments,
- Continuation continuation,
[this.sourceInformation])
: this.receiver = new Reference<Primitive>(receiver),
- this.arguments = _referenceList(arguments),
- this.continuation = new Reference<Continuation>(continuation);
+ this.arguments = _referenceList(arguments);
InvokeMethod.byReference(this.receiver,
this.selector,
this.mask,
this.arguments,
- this.continuation,
this.sourceInformation);
accept(Visitor visitor) => visitor.visitInvokeMethod(this);
+ bool get hasValue => true;
+
void setParentPointers() {
receiver.parent = this;
_setParentsOnList(arguments, this);
- continuation.parent = this;
}
}
@@ -540,30 +588,46 @@
///
/// All optional arguments declared by [target] are passed in explicitly, and
/// occur at the end of [arguments] list, in normalized order.
-class InvokeMethodDirectly extends CallExpression {
+class InvokeMethodDirectly extends UnsafePrimitive {
Reference<Primitive> receiver;
final FunctionElement target;
final Selector selector;
final List<Reference<Primitive>> arguments;
- final Reference<Continuation> continuation;
final SourceInformation sourceInformation;
+ CallingConvention callingConvention = CallingConvention.Normal;
+
+ Reference<Primitive> get dartReceiverReference {
+ return callingConvention == CallingConvention.Intercepted
+ ? arguments[0]
+ : receiver;
+ }
+
+ Primitive get dartReceiver => dartReceiverReference.definition;
+
+ Reference<Primitive> dartArgumentReference(int n) {
+ return callingConvention == CallingConvention.Normal
+ ? arguments[n]
+ : arguments[n + 1];
+ }
+
+ Primitive dartArgument(int n) => dartArgumentReference(n).definition;
+
InvokeMethodDirectly(Primitive receiver,
this.target,
this.selector,
List<Primitive> arguments,
- Continuation continuation,
this.sourceInformation)
: this.receiver = new Reference<Primitive>(receiver),
- this.arguments = _referenceList(arguments),
- this.continuation = new Reference<Continuation>(continuation);
+ this.arguments = _referenceList(arguments);
accept(Visitor visitor) => visitor.visitInvokeMethodDirectly(this);
+ bool get hasValue => true;
+
void setParentPointers() {
receiver.parent = this;
_setParentsOnList(arguments, this);
- continuation.parent = this;
}
}
@@ -582,11 +646,10 @@
///
/// Note that [InvokeConstructor] does it itself allocate an object.
/// The invoked constructor will do that using [CreateInstance].
-class InvokeConstructor extends CallExpression {
+class InvokeConstructor extends UnsafePrimitive {
final DartType dartType;
final ConstructorElement target;
final List<Reference<Primitive>> arguments;
- final Reference<Continuation> continuation;
final Selector selector;
final SourceInformation sourceInformation;
@@ -601,17 +664,16 @@
this.target,
this.selector,
List<Primitive> args,
- Continuation cont,
this.sourceInformation,
{this.allocationSiteType})
- : arguments = _referenceList(args),
- continuation = new Reference<Continuation>(cont);
+ : arguments = _referenceList(args);
accept(Visitor visitor) => visitor.visitInvokeConstructor(this);
+ bool get hasValue => true;
+
void setParentPointers() {
_setParentsOnList(arguments, this);
- continuation.parent = this;
}
}
@@ -629,6 +691,7 @@
Refinement(Primitive value, this.refineType)
: value = new Reference<Primitive>(value);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => false;
@@ -665,12 +728,6 @@
/// Otherwise the list is empty.
final List<Reference<Primitive>> typeArguments;
- /// The Interceptor for [value]. May be `null` if the test can be done
- /// without an interceptor. May be the same as [value] after self-interceptor
- /// optimization.
- // TODO(24523): Remove this field.
- Reference<Primitive> interceptor;
-
TypeTest(Primitive value,
this.dartType,
List<Primitive> typeArguments)
@@ -679,13 +736,13 @@
accept(Visitor visitor) => visitor.visitTypeTest(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
void setParentPointers() {
value.parent = this;
_setParentsOnList(typeArguments, this);
- if (interceptor != null) interceptor.parent = this;
}
}
@@ -701,6 +758,7 @@
accept(Visitor visitor) => visitor.visitTypeTestViaFlag(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -719,26 +777,26 @@
/// [value], which is typically in scope in the continuation. However, it might
/// simplify type propagation, since a better type can be computed for the
/// continuation parameter without needing flow-sensitive analysis.
-class TypeCast extends CallExpression {
+class TypeCast extends UnsafePrimitive {
Reference<Primitive> value;
final DartType dartType;
/// See the corresponding field on [TypeTest].
final List<Reference<Primitive>> typeArguments;
- final Reference<Continuation> continuation;
TypeCast(Primitive value,
this.dartType,
- List<Primitive> typeArguments,
- Continuation cont)
+ List<Primitive> typeArguments)
: this.value = new Reference<Primitive>(value),
- this.typeArguments = _referenceList(typeArguments),
- this.continuation = new Reference<Continuation>(cont);
+ this.typeArguments = _referenceList(typeArguments);
accept(Visitor visitor) => visitor.visitTypeCast(this);
+ bool get hasValue => true;
+
void setParentPointers() {
value.parent = this;
+ _setParentsOnList(typeArguments, this);
}
}
@@ -757,6 +815,7 @@
accept(Visitor visitor) => visitor.visitApplyBuiltinOperator(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -786,6 +845,7 @@
accept(Visitor visitor) => visitor.visitApplyBuiltinMethod(this);
+ bool get hasValue => true;
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
@@ -845,6 +905,7 @@
accept(Visitor visitor) => visitor.visitGetMutable(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => false;
@@ -869,6 +930,7 @@
accept(Visitor visitor) => visitor.visitSetMutable(this);
+ bool get hasValue => false;
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
@@ -973,6 +1035,7 @@
accept(Visitor visitor) => visitor.visitSetField(this);
+ bool get hasValue => false;
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
@@ -999,6 +1062,7 @@
accept(Visitor visitor) => visitor.visitGetField(this);
+ bool get hasValue => true;
bool get isSafeForElimination => objectIsNotNull;
bool get isSafeForReordering => false;
@@ -1018,6 +1082,7 @@
GetLength(Primitive object) : this.object = new Reference<Primitive>(object);
+ bool get hasValue => true;
bool get isSafeForElimination => objectIsNotNull;
bool get isSafeForReordering => false;
@@ -1043,6 +1108,7 @@
: this.object = new Reference<Primitive>(object),
this.index = new Reference<Primitive>(index);
+ bool get hasValue => true;
bool get isSafeForElimination => objectIsNotNull;
bool get isSafeForReordering => false;
@@ -1069,6 +1135,7 @@
this.index = new Reference<Primitive>(index),
this.value = new Reference<Primitive>(value);
+ bool get hasValue => false;
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
@@ -1093,9 +1160,8 @@
accept(Visitor visitor) => visitor.visitGetStatic(this);
- bool get isSafeForElimination {
- return true;
- }
+ bool get hasValue => true;
+ bool get isSafeForElimination => true;
bool get isSafeForReordering {
return element is FunctionElement || element.isFinal;
}
@@ -1114,6 +1180,7 @@
accept(Visitor visitor) => visitor.visitSetStatic(this);
+ bool get hasValue => false;
bool get isSafeForElimination => false;
bool get isSafeForReordering => false;
@@ -1126,29 +1193,24 @@
///
/// If the field has not yet been initialized, its initializer is evaluated
/// and assigned to the field.
-///
-/// [continuation] is then invoked with the value of the field as argument.
-class GetLazyStatic extends CallExpression {
+class GetLazyStatic extends UnsafePrimitive {
final FieldElement element;
- final Reference<Continuation> continuation;
final SourceInformation sourceInformation;
- GetLazyStatic(this.element,
- Continuation continuation,
- [this.sourceInformation])
- : continuation = new Reference<Continuation>(continuation);
+ GetLazyStatic(this.element, [this.sourceInformation]);
accept(Visitor visitor) => visitor.visitGetLazyStatic(this);
- void setParentPointers() {
- continuation.parent = this;
- }
+ bool get hasValue => true;
+
+ void setParentPointers() {}
}
/// Creates an object for holding boxed variables captured by a closure.
class CreateBox extends Primitive {
accept(Visitor visitor) => visitor.visitCreateBox(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1181,6 +1243,7 @@
accept(Visitor visitor) => visitor.visitCreateInstance(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1277,6 +1340,7 @@
accept(Visitor visitor) => visitor.visitInterceptor(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1295,6 +1359,7 @@
accept(Visitor visitor) => visitor.visitCreateInvocationMirror(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1303,24 +1368,23 @@
}
}
-class ForeignCode extends CallExpression {
+class ForeignCode extends UnsafePrimitive {
final js.Template codeTemplate;
final TypeMask type;
final List<Reference<Primitive>> arguments;
final native.NativeBehavior nativeBehavior;
final FunctionElement dependency;
- final Reference<Continuation> continuation;
ForeignCode(this.codeTemplate, this.type, List<Primitive> arguments,
- this.nativeBehavior, Continuation continuation, {this.dependency})
- : this.arguments = _referenceList(arguments),
- this.continuation = new Reference<Continuation>(continuation);
+ this.nativeBehavior, {this.dependency})
+ : this.arguments = _referenceList(arguments);
accept(Visitor visitor) => visitor.visitForeignCode(this);
+ bool get hasValue => true;
+
void setParentPointers() {
_setParentsOnList(arguments, this);
- continuation.parent = this;
}
}
@@ -1334,6 +1398,7 @@
accept(Visitor visitor) => visitor.visitConstant(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1354,6 +1419,7 @@
accept(Visitor visitor) => visitor.visitLiteralList(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1379,6 +1445,7 @@
accept(Visitor visitor) => visitor.visitLiteralMap(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1390,29 +1457,6 @@
}
}
-/// Currently unused.
-///
-/// Nested functions (from Dart code) are translated to classes by closure
-/// conversion, hence they are instantiated with [CreateInstance].
-///
-/// We keep this around for now because it might come in handy when we
-/// handle async/await in the CPS IR.
-///
-/// Instantiates a nested function. [MutableVariable]s are in scope in the
-/// inner function, but primitives are not shared across function boundaries.
-class CreateFunction extends Primitive {
- final FunctionDefinition definition;
-
- CreateFunction(this.definition);
-
- accept(Visitor visitor) => visitor.visitCreateFunction(this);
-
- bool get isSafeForElimination => true;
- bool get isSafeForReordering => true;
-
- void setParentPointers() {}
-}
-
class Parameter extends Primitive {
Parameter(Entity hint) {
super.hint = hint;
@@ -1422,6 +1466,7 @@
String toString() => 'Parameter(${hint == null ? null : hint.name})';
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1515,6 +1560,7 @@
@override
accept(Visitor visitor) => visitor.visitReifyRuntimeType(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1539,6 +1585,7 @@
@override
accept(Visitor visitor) => visitor.visitReadTypeVariable(this);
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1568,6 +1615,7 @@
return visitor.visitTypeExpression(this);
}
+ bool get hasValue => true;
bool get isSafeForElimination => true;
bool get isSafeForReordering => true;
@@ -1576,42 +1624,40 @@
}
}
-class Await extends CallExpression {
+class Await extends UnsafePrimitive {
final Reference<Primitive> input;
- final Reference<Continuation> continuation;
- Await(Primitive input, Continuation continuation)
- : this.input = new Reference<Primitive>(input),
- this.continuation = new Reference<Continuation>(continuation);
+ Await(Primitive input)
+ : this.input = new Reference<Primitive>(input);
@override
accept(Visitor visitor) {
return visitor.visitAwait(this);
}
+ bool get hasValue => true;
+
void setParentPointers() {
input.parent = this;
- continuation.parent = this;
}
}
-class Yield extends CallExpression {
+class Yield extends UnsafePrimitive {
final Reference<Primitive> input;
- final Reference<Continuation> continuation;
final bool hasStar;
- Yield(Primitive input, this.hasStar, Continuation continuation)
- : this.input = new Reference<Primitive>(input),
- this.continuation = new Reference<Continuation>(continuation);
+ Yield(Primitive input, this.hasStar)
+ : this.input = new Reference<Primitive>(input);
@override
accept(Visitor visitor) {
return visitor.visitYield(this);
}
+ bool get hasValue => true;
+
void setParentPointers() {
input.parent = this;
- continuation.parent = this;
}
}
@@ -1665,7 +1711,6 @@
T visitLiteralList(LiteralList node);
T visitLiteralMap(LiteralMap node);
T visitConstant(Constant node);
- T visitCreateFunction(CreateFunction node);
T visitGetMutable(GetMutable node);
T visitParameter(Parameter node);
T visitContinuation(Continuation node);
@@ -1760,7 +1805,6 @@
processInvokeStatic(InvokeStatic node) {}
visitInvokeStatic(InvokeStatic node) {
processInvokeStatic(node);
- processReference(node.continuation);
node.arguments.forEach(processReference);
}
@@ -1775,7 +1819,6 @@
visitInvokeMethod(InvokeMethod node) {
processInvokeMethod(node);
processReference(node.receiver);
- processReference(node.continuation);
node.arguments.forEach(processReference);
}
@@ -1783,14 +1826,12 @@
visitInvokeMethodDirectly(InvokeMethodDirectly node) {
processInvokeMethodDirectly(node);
processReference(node.receiver);
- processReference(node.continuation);
node.arguments.forEach(processReference);
}
processInvokeConstructor(InvokeConstructor node) {}
visitInvokeConstructor(InvokeConstructor node) {
processInvokeConstructor(node);
- processReference(node.continuation);
node.arguments.forEach(processReference);
}
@@ -1816,7 +1857,6 @@
processTypeCast(TypeCast node) {}
visitTypeCast(TypeCast node) {
processTypeCast(node);
- processReference(node.continuation);
processReference(node.value);
node.typeArguments.forEach(processReference);
}
@@ -1825,7 +1865,6 @@
visitTypeTest(TypeTest node) {
processTypeTest(node);
processReference(node.value);
- if (node.interceptor != null) processReference(node.interceptor);
node.typeArguments.forEach(processReference);
}
@@ -1845,7 +1884,6 @@
processGetLazyStatic(GetLazyStatic node) {}
visitGetLazyStatic(GetLazyStatic node) {
processGetLazyStatic(node);
- processReference(node.continuation);
}
processLiteralList(LiteralList node) {}
@@ -1868,12 +1906,6 @@
processConstant(node);
}
- processCreateFunction(CreateFunction node) {}
- visitCreateFunction(CreateFunction node) {
- processCreateFunction(node);
- visit(node.definition);
- }
-
processMutableVariable(node) {}
visitMutableVariable(MutableVariable node) {
processMutableVariable(node);
@@ -1972,9 +2004,6 @@
processForeignCode(ForeignCode node) {}
visitForeignCode(ForeignCode node) {
processForeignCode(node);
- if (node.continuation != null) {
- processReference(node.continuation);
- }
node.arguments.forEach(processReference);
}
@@ -1987,14 +2016,12 @@
visitAwait(Await node) {
processAwait(node);
processReference(node.input);
- processReference(node.continuation);
}
processYield(Yield node) {}
visitYield(Yield node) {
processYield(node);
processReference(node.input);
- processReference(node.continuation);
}
processGetLength(GetLength node) {}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
index 79164b5..78b976f 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_nodes_sexpr.dart
@@ -108,10 +108,12 @@
}
String formatArguments(CallStructure call,
- List<Reference<Primitive>> arguments,
- {bool isIntercepted: false}) {
+ List<Reference<Primitive>> arguments,
+ [CallingConvention callingConvention = CallingConvention.Normal]) {
int positionalArgumentCount = call.positionalArgumentCount;
- if (isIntercepted) ++positionalArgumentCount;
+ if (callingConvention == CallingConvention.Intercepted) {
+ ++positionalArgumentCount;
+ }
List<String> args =
arguments.getRange(0, positionalArgumentCount).map(access).toList();
List<String> argumentNames = call.getOrderedNamedArguments();
@@ -125,26 +127,24 @@
String visitInvokeStatic(InvokeStatic node) {
String name = node.target.name;
- String cont = access(node.continuation);
String args = formatArguments(node.selector.callStructure, node.arguments);
- return '$indentation(InvokeStatic $name $args $cont)';
+ return '(InvokeStatic $name $args)';
}
String visitInvokeMethod(InvokeMethod node) {
String name = node.selector.name;
String rcv = access(node.receiver);
- String cont = access(node.continuation);
String args = formatArguments(node.selector.callStructure, node.arguments,
- isIntercepted: node.receiverIsIntercepted);
- return '$indentation(InvokeMethod $rcv $name $args $cont)';
+ node.callingConvention);
+ return '(InvokeMethod $rcv $name $args)';
}
String visitInvokeMethodDirectly(InvokeMethodDirectly node) {
String receiver = access(node.receiver);
String name = node.selector.name;
- String cont = access(node.continuation);
- String args = formatArguments(node.selector.callStructure, node.arguments);
- return '$indentation(InvokeMethodDirectly $receiver $name $args $cont)';
+ String args = formatArguments(node.selector.callStructure, node.arguments,
+ node.callingConvention);
+ return '(InvokeMethodDirectly $receiver $name $args)';
}
String visitInvokeConstructor(InvokeConstructor node) {
@@ -164,9 +164,8 @@
} else {
callName = '${className}.${node.target.name}';
}
- String cont = access(node.continuation);
String args = formatArguments(node.selector.callStructure, node.arguments);
- return '$indentation(InvokeConstructor $callName $args $cont)';
+ return '(InvokeConstructor $callName $args)';
}
String visitInvokeContinuation(InvokeContinuation node) {
@@ -202,12 +201,6 @@
return '(Constant $value)';
}
- String visitCreateFunction(CreateFunction node) {
- String function =
- indentBlock(() => indentBlock(() => visit(node.definition)));
- return '(CreateFunction\n$function)';
- }
-
String visitContinuation(Continuation node) {
String name = newContinuationName(node);
if (node.isRecursive) name = 'rec $name';
@@ -232,19 +225,14 @@
String visitTypeCast(TypeCast node) {
String value = access(node.value);
- String cont = access(node.continuation);
String typeArguments = node.typeArguments.map(access).join(' ');
- return '$indentation(TypeCast $value ${node.dartType}'
- ' ($typeArguments) $cont)';
+ return '(TypeCast $value ${node.dartType} ($typeArguments))';
}
String visitTypeTest(TypeTest node) {
String value = access(node.value);
String typeArguments = node.typeArguments.map(access).join(' ');
- String interceptor = node.interceptor == null
- ? ''
- : access(node.interceptor);
- return '(TypeTest $value ${node.dartType} ($typeArguments) ($interceptor))';
+ return '(TypeTest $value ${node.dartType} ($typeArguments))';
}
String visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -289,8 +277,7 @@
String visitGetLazyStatic(GetLazyStatic node) {
String element = node.element.name;
- String cont = access(node.continuation);
- return '$indentation(GetLazyStatic $element $cont)';
+ return '(GetLazyStatic $element)';
}
String visitCreateBox(CreateBox node) {
@@ -342,10 +329,7 @@
String visitForeignCode(ForeignCode node) {
String arguments = node.arguments.map(access).join(' ');
- String continuation = node.continuation == null ? ''
- : ' ${access(node.continuation)}';
- return '$indentation(JS "${node.codeTemplate.source}"'
- ' ($arguments)$continuation)';
+ return '(JS "${node.codeTemplate.source}" ($arguments))';
}
String visitGetLength(GetLength node) {
@@ -369,15 +353,13 @@
@override
String visitAwait(Await node) {
String value = access(node.input);
- String continuation = access(node.continuation);
- return '(Await $value $continuation)';
+ return '(Await $value)';
}
@override
String visitYield(Yield node) {
String value = access(node.input);
- String continuation = access(node.continuation);
- return '(Yield $value $continuation)';
+ return '(Yield $value)';
}
String visitRefinement(Refinement node) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
index 12a6a31..6c7469e 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_tracer.dart
@@ -140,35 +140,26 @@
}
visitInvokeStatic(cps_ir.InvokeStatic node) {
- String dummy = names.name(node);
String callName = node.selector.name;
String args = node.arguments.map(formatReference).join(', ');
- String kont = formatReference(node.continuation);
- printStmt(dummy, "InvokeStatic $callName ($args) $kont");
+ return "InvokeStatic $callName ($args)";
}
visitInvokeMethod(cps_ir.InvokeMethod node) {
- String dummy = names.name(node);
String receiver = formatReference(node.receiver);
String callName = node.selector.name;
String args = node.arguments.map(formatReference).join(', ');
- String kont = formatReference(node.continuation);
- printStmt(dummy,
- "InvokeMethod $receiver $callName ($args) $kont");
+ return "InvokeMethod $receiver $callName ($args)";
}
visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- String dummy = names.name(node);
String receiver = formatReference(node.receiver);
String callName = node.selector.name;
String args = node.arguments.map(formatReference).join(', ');
- String kont = formatReference(node.continuation);
- printStmt(dummy,
- "InvokeMethodDirectly $receiver $callName ($args) $kont");
+ return "InvokeMethodDirectly $receiver $callName ($args)";
}
visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- String dummy = names.name(node);
String className = node.target.enclosingClass.name;
String callName;
if (node.target.name.isEmpty) {
@@ -177,8 +168,7 @@
callName = '${className}.${node.target.name}';
}
String args = node.arguments.map(formatReference).join(', ');
- String kont = formatReference(node.continuation);
- printStmt(dummy, "InvokeConstructor $callName ($args) $kont");
+ return "InvokeConstructor $callName ($args)";
}
visitThrow(cps_ir.Throw node) {
@@ -213,11 +203,9 @@
}
visitTypeCast(cps_ir.TypeCast node) {
- String dummy = names.name(node);
String value = formatReference(node.value);
String args = node.typeArguments.map(formatReference).join(', ');
- String kont = formatReference(node.continuation);
- printStmt(dummy, "TypeCast ($value ${node.dartType} ($args)) $kont");
+ return "TypeCast ($value ${node.dartType} ($args))";
}
visitInvokeContinuation(cps_ir.InvokeContinuation node) {
@@ -237,18 +225,14 @@
}
visitAwait(cps_ir.Await node) {
- String dummy = names.name(node);
String value = formatReference(node.input);
- String continuation = formatReference(node.continuation);
- printStmt(dummy, 'Await $value $continuation');
+ return 'Await $value';
}
visitYield(cps_ir.Yield node) {
- String dummy = names.name(node);
String name = node.hasStar ? 'YieldStar' : 'Yield';
String value = formatReference(node.input);
- String continuation = formatReference(node.continuation);
- printStmt(dummy, '$name $value $continuation');
+ return '$name $value';
}
visitSetMutable(cps_ir.SetMutable node) {
@@ -307,9 +291,8 @@
}
visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- String dummy = names.name(node);
- String kont = formatReference(node.continuation);
- printStmt(dummy, "GetLazyStatic $kont");
+ String element = node.element.name;
+ return "GetLazyStatic $element";
}
visitCreateBox(cps_ir.CreateBox node) {
@@ -329,10 +312,6 @@
'${node.interceptedClasses})';
}
- visitCreateFunction(cps_ir.CreateFunction node) {
- return "CreateFunction ${node.definition.element.name}";
- }
-
visitGetMutable(cps_ir.GetMutable node) {
String variable = names.name(node.variable.definition);
return 'GetMutable $variable';
@@ -360,10 +339,7 @@
visitTypeTest(cps_ir.TypeTest node) {
String value = formatReference(node.value);
String args = node.typeArguments.map(formatReference).join(', ');
- String interceptor = node.interceptor == null
- ? ''
- : ' ${formatReference(node.interceptor)}';
- return "TypeTest ($value ${node.dartType} ($args)$interceptor)";
+ return "TypeTest ($value ${node.dartType} ($args))";
}
visitTypeTestViaFlag(cps_ir.TypeTestViaFlag node) {
@@ -384,13 +360,11 @@
return 'ApplyBuiltinMethod $method $receiver ($args)';
}
- @override
visitForeignCode(cps_ir.ForeignCode node) {
String id = names.name(node);
String arguments = node.arguments.map(formatReference).join(', ');
- String continuation = formatReference(node.continuation);
- printStmt(id, "ForeignCode ${node.type} ${node.codeTemplate.source} "
- "$arguments $continuation");
+ printStmt(id,
+ "ForeignCode ${node.type} ${node.codeTemplate.source} $arguments");
}
visitGetLength(cps_ir.GetLength node) {
@@ -411,7 +385,6 @@
return 'SetIndex $object $index $value';
}
- @override
visitRefinement(cps_ir.Refinement node) {
String value = formatReference(node.value);
return 'Refinement $value ${node.refineType}';
@@ -526,20 +499,20 @@
addEdgeToContinuation(exp.continuation);
}
- visitInvokeStatic(cps_ir.InvokeStatic exp) {
- addEdgeToContinuation(exp.continuation);
+ visitInvokeStatic(cps_ir.InvokeStatic node) {
+ unexpectedNode(node);
}
- visitInvokeMethod(cps_ir.InvokeMethod exp) {
- addEdgeToContinuation(exp.continuation);
+ visitInvokeMethod(cps_ir.InvokeMethod node) {
+ unexpectedNode(node);
}
- visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly exp) {
- addEdgeToContinuation(exp.continuation);
+ visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
+ unexpectedNode(node);
}
- visitInvokeConstructor(cps_ir.InvokeConstructor exp) {
- addEdgeToContinuation(exp.continuation);
+ visitInvokeConstructor(cps_ir.InvokeConstructor node) {
+ unexpectedNode(node);
}
visitThrow(cps_ir.Throw exp) {
@@ -551,8 +524,8 @@
visitUnreachable(cps_ir.Unreachable node) {
}
- visitGetLazyStatic(cps_ir.GetLazyStatic exp) {
- addEdgeToContinuation(exp.continuation);
+ visitGetLazyStatic(cps_ir.GetLazyStatic node) {
+ unexpectedNode(node);
}
visitBranch(cps_ir.Branch exp) {
@@ -566,8 +539,8 @@
}
}
- visitTypeCast(cps_ir.TypeCast exp) {
- addEdgeToContinuation(exp.continuation);
+ visitTypeCast(cps_ir.TypeCast node) {
+ unexpectedNode(node);
}
visitContinuation(cps_ir.Continuation c) {
@@ -595,10 +568,6 @@
unexpectedNode(node);
}
- visitCreateFunction(cps_ir.CreateFunction node) {
- unexpectedNode(node);
- }
-
visitGetMutable(cps_ir.GetMutable node) {
unexpectedNode(node);
}
@@ -687,22 +656,18 @@
unexpectedNode(node);
}
- @override
visitForeignCode(cps_ir.ForeignCode node) {
- addEdgeToContinuation(node.continuation);
+ unexpectedNode(node);
}
- @override
visitAwait(cps_ir.Await node) {
- addEdgeToContinuation(node.continuation);
+ unexpectedNode(node);
}
- @override
visitYield(cps_ir.Yield node) {
- addEdgeToContinuation(node.continuation);
+ unexpectedNode(node);
}
- @override
visitRefinement(cps_ir.Refinement node) {
unexpectedNode(node);
}
diff --git a/pkg/compiler/lib/src/cps_ir/gvn.dart b/pkg/compiler/lib/src/cps_ir/gvn.dart
new file mode 100644
index 0000000..02379d8
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/gvn.dart
@@ -0,0 +1,706 @@
+// 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 dart2js.cps_ir.gvn;
+
+import 'cps_ir_nodes.dart';
+import '../universe/side_effects.dart';
+import '../elements/elements.dart';
+import 'optimizers.dart' show Pass;
+import 'loop_hierarchy.dart';
+import 'loop_effects.dart';
+import '../world.dart';
+import '../compiler.dart' show Compiler;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../constants/values.dart';
+
+/// Eliminates redundant primitives by reusing the value of another primitive
+/// that is known to have the same result. Primitives are also hoisted out of
+/// loops when possible.
+///
+/// Reusing values can introduce new temporaries, which in some cases is more
+/// expensive than recomputing the value on-demand. For example, pulling an
+/// expression such as "n+1" out of a loop is generally not worth it.
+/// Such primitives are said to be "trivial".
+///
+/// Trivial primitives are shared on-demand, i.e. they are only shared if
+/// this enables a non-trivial primitive to be hoisted out of a loop.
+//
+// TODO(asgerf): Enable hoisting across refinement guards when this is safe:
+// - Determine the type required for a given primitive to be "safe"
+// - Recompute the type of a primitive after hoisting.
+// E.g. GetIndex on a String can become a GetIndex on an arbitrary
+// indexable, which is still safe but the type may change
+// - Since the new type may be worse, insert a refinement at the old
+// definition site, so we do not degrade existing type information.
+//
+// TODO(asgerf): Put this pass at a better place in the pipeline. We currently
+// cannot put it anywhere we want, because this pass relies on refinement
+// nodes being present (for safety), whereas other passes rely on refinement
+// nodes being absent (for simplicity & precision).
+//
+class GVN extends TrampolineRecursiveVisitor implements Pass {
+ String get passName => 'GVN';
+
+ final Compiler compiler;
+ JavaScriptBackend get backend => compiler.backend;
+ World get world => compiler.world;
+
+ final GvnTable gvnTable = new GvnTable();
+ GvnVectorBuilder gvnVectorBuilder;
+ LoopHierarchy loopHierarchy;
+ LoopSideEffects loopEffects;
+
+ /// Effect numbers at the given join point.
+ Map<Continuation, EffectNumbers> effectsAt = <Continuation, EffectNumbers>{};
+
+ /// The effect numbers at the current position (during traversal).
+ EffectNumbers effectNumbers = new EffectNumbers();
+
+ /// The loop currently enclosing the binding of a given primitive.
+ final Map<Primitive, Continuation> loopHeaderFor =
+ <Primitive, Continuation>{};
+
+ /// The loop to which a given trivial primitive can be hoisted.
+ final Map<Primitive, Continuation> potentialLoopHeaderFor =
+ <Primitive, Continuation>{};
+
+ /// The GVNs for primitives that have been hoisted outside the given loop.
+ ///
+ /// These should be removed from the environment when exiting the loop.
+ final Map<Continuation, List<int>> loopHoistedBindings =
+ <Continuation, List<int>>{};
+
+ /// Maps GVNs to a currently-in-scope binding for that value.
+ final Map<int, Primitive> environment = <int, Primitive>{};
+
+ /// Maps GVN'able primitives to their global value number.
+ final Map<Primitive, int> gvnFor = <Primitive, int>{};
+
+ Continuation currentLoopHeader;
+
+ GVN(this.compiler);
+
+ int _usedEffectNumbers = 0;
+ int makeNewEffect() => ++_usedEffectNumbers;
+
+ void rewrite(FunctionDefinition node) {
+ gvnVectorBuilder = new GvnVectorBuilder(gvnFor, backend);
+ loopHierarchy = new LoopHierarchy(node);
+ loopEffects =
+ new LoopSideEffects(node, world, loopHierarchy: loopHierarchy);
+ visit(node);
+ }
+
+ // ------------------ GLOBAL VALUE NUMBERING ---------------------
+
+ @override
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ Primitive prim = node.primitive;
+
+ loopHeaderFor[prim] = currentLoopHeader;
+
+ if (prim is Refinement) {
+ // Do not share refinements (they have no runtime or code size cost), and
+ // do not put them in the GVN table because GvnVectorBuilder unfolds
+ // refinements by itself.
+ return next;
+ }
+
+ // Compute the GVN vector for this computation.
+ List vector = gvnVectorBuilder.make(prim, effectNumbers);
+
+ // Update effect numbers due to side effects.
+ // Do this after computing the GVN vector so the primitive's GVN is not
+ // influenced by its own side effects.
+ visit(prim);
+
+ if (vector == null) {
+ // The primitive is not GVN'able. Move on.
+ return next;
+ }
+
+ // Compute the GVN for this primitive.
+ int gvn = gvnTable.insert(vector);
+ gvnFor[prim] = gvn;
+
+ // Try to reuse a previously computed value with the same GVN.
+ Primitive existing = environment[gvn];
+ if (existing != null &&
+ (prim.isSafeForElimination || prim is GetLazyStatic) &&
+ !isTrivialPrimitive(prim)) {
+ if (prim is Interceptor) {
+ Interceptor interceptor = existing;
+ interceptor.interceptedClasses.addAll(prim.interceptedClasses);
+ interceptor.flags |= prim.flags;
+ }
+ prim..replaceUsesWith(existing)..destroy();
+ node.remove();
+ return next;
+ }
+
+ if (tryToHoistOutOfLoop(prim, gvn)) {
+ return next;
+ }
+
+ // The primitive could not be hoisted. Put the primitive in the
+ // environment while processing the body of the LetPrim.
+ environment[gvn] = prim;
+ pushAction(() {
+ assert(environment[gvn] == prim);
+ environment[gvn] = existing;
+ });
+
+ return next;
+ }
+
+ /// Try to hoist the binding of [prim] out of loops. Returns `true` if it was
+ /// hoisted or marked as a trivial hoist-on-demand primitive.
+ bool tryToHoistOutOfLoop(Primitive prim, int gvn) {
+ // Do not hoist primitives with side effects.
+ if (!prim.isSafeForElimination) return false;
+
+ // Bail out fast if the primitive is not inside a loop.
+ if (currentLoopHeader == null) return false;
+
+ LetPrim letPrim = prim.parent;
+
+ // Find the depth of the outermost scope where we can bind the primitive
+ // without bringing a reference out of scope. 0 is the depth of the
+ // top-level scope.
+ int hoistDepth = 0;
+ List<Primitive> inputsHoistedOnDemand = <Primitive>[];
+ InputVisitor.forEach(prim, (Reference ref) {
+ Primitive input = ref.definition;
+ if (canIgnoreRefinementGuards(prim)) {
+ input = input.effectiveDefinition;
+ }
+ Continuation loopHeader;
+ if (potentialLoopHeaderFor.containsKey(input)) {
+ // This is a reference to a value that can be hoisted further out than
+ // it currently is. If we decide to hoist [prim], we must also hoist
+ // such dependent values.
+ loopHeader = potentialLoopHeaderFor[input];
+ inputsHoistedOnDemand.add(input);
+ } else {
+ loopHeader = loopHeaderFor[input];
+ }
+ Continuation referencedLoop =
+ loopHierarchy.lowestCommonAncestor(loopHeader, currentLoopHeader);
+ int depth = loopHierarchy.getDepth(referencedLoop);
+ if (depth > hoistDepth) {
+ hoistDepth = depth;
+ }
+ });
+
+ // Bail out if it can not be hoisted further out than it is now.
+ if (hoistDepth == loopHierarchy.getDepth(currentLoopHeader)) return false;
+
+ // Walk up the loop hierarchy and check at every step that any heap
+ // dependencies can safely be hoisted out of the loop.
+ Continuation enclosingLoop = currentLoopHeader;
+ Continuation hoistTarget = null;
+ while (loopHierarchy.getDepth(enclosingLoop) > hoistDepth &&
+ canHoistHeapDependencyOutOfLoop(prim, enclosingLoop)) {
+ hoistTarget = enclosingLoop;
+ enclosingLoop = loopHierarchy.getEnclosingLoop(enclosingLoop);
+ }
+
+ // Bail out if heap dependencies prohibit any hoisting at all.
+ if (hoistTarget == null) return false;
+
+ if (isTrivialPrimitive(prim)) {
+ // The overhead from introducting a temporary might be greater than
+ // the overhead of evaluating this primitive at every iteration.
+ // Only hoist if this enables hoisting of a non-trivial primitive.
+ potentialLoopHeaderFor[prim] = enclosingLoop;
+ return true;
+ }
+
+ LetCont loopBinding = hoistTarget.parent;
+
+ // The primitive may depend on values that have not yet been
+ // hoisted as far as they can. Hoist those now.
+ for (Primitive input in inputsHoistedOnDemand) {
+ hoistTrivialPrimitive(input, loopBinding, enclosingLoop);
+ }
+
+ // Hoist the primitive.
+ letPrim.remove();
+ letPrim.insertAbove(loopBinding);
+ loopHeaderFor[prim] = enclosingLoop;
+
+ // If a refinement guard was bypassed, use the best refinement
+ // currently in scope.
+ if (canIgnoreRefinementGuards(prim)) {
+ int target = loopHierarchy.getDepth(enclosingLoop);
+ InputVisitor.forEach(prim, (Reference ref) {
+ Primitive input = ref.definition;
+ while (input is Refinement) {
+ Continuation loop = loopHeaderFor[input];
+ loop = loopHierarchy.lowestCommonAncestor(loop, currentLoopHeader);
+ if (loopHierarchy.getDepth(loop) <= target) break;
+ Refinement refinement = input;
+ input = refinement.value.definition;
+ }
+ ref.changeTo(input);
+ });
+ }
+
+ // Put the primitive in the environment while processing the loop.
+ environment[gvn] = prim;
+ loopHoistedBindings
+ .putIfAbsent(hoistTarget, () => <int>[])
+ .add(gvn);
+ return true;
+ }
+
+ /// If the given primitive is a trivial primitive that should be hoisted
+ /// on-demand, hoist it and its dependent values above [loopBinding].
+ void hoistTrivialPrimitive(Primitive prim,
+ LetCont loopBinding,
+ Continuation enclosingLoop) {
+ if (!potentialLoopHeaderFor.containsKey(prim)) return;
+ assert(isTrivialPrimitive(prim));
+
+ // The primitive might already be bound in an outer scope. Do not relocate
+ // the primitive unless we are lifting it. For example;
+ // t1 = a + b
+ // t2 = t1 + c
+ // t3 = t1 * t2
+ // If it was decided that `t3` should be hoisted, `t1` will be seen twice by
+ // this method: by the direct reference and by reference through `t2`.
+ // The second time it is seen, it will already have been moved.
+ Continuation currentLoop = loopHeaderFor[prim];
+ int currentDepth = loopHierarchy.getDepth(currentLoop);
+ int targetDepth = loopHierarchy.getDepth(enclosingLoop);
+ if (currentDepth <= targetDepth) return;
+
+ // Hoist the trivial primitives being depended on so they remain in scope.
+ InputVisitor.forEach(prim, (Reference ref) {
+ hoistTrivialPrimitive(ref.definition, loopBinding, enclosingLoop);
+ });
+
+ // Move the primitive.
+ LetPrim binding = prim.parent;
+ binding.remove();
+ binding.insertAbove(loopBinding);
+ loopHeaderFor[prim] = enclosingLoop;
+
+ if (potentialLoopHeaderFor[prim] == enclosingLoop) {
+ potentialLoopHeaderFor.remove(prim);
+ }
+ }
+
+ bool canIgnoreRefinementGuards(Primitive primitive) {
+ return primitive is Interceptor;
+ }
+
+ /// Returns true if the given primitive is so cheap at runtime that it is
+ /// better to (redundantly) recompute it rather than introduce a temporary.
+ bool isTrivialPrimitive(Primitive primitive) {
+ return primitive is ApplyBuiltinOperator ||
+ primitive is Constant && isTrivialConstant(primitive.value);
+ }
+
+ /// Returns true if the given constant has almost no runtime cost.
+ bool isTrivialConstant(ConstantValue value) {
+ return value.isPrimitive || value.isDummy;
+ }
+
+ /// True if [element] is a final or constant field or a function.
+ bool isImmutable(Element element) {
+ if (element.isField && backend.isNative(element)) return false;
+ return element.isField && (element.isFinal || element.isConst) ||
+ element.isFunction;
+ }
+
+ /// Assuming [prim] has no side effects, returns true if it can safely
+ /// be hoisted out of [loop] without changing its value.
+ bool canHoistHeapDependencyOutOfLoop(Primitive prim, Continuation loop) {
+ assert(prim.isSafeForElimination);
+ if (prim is GetLength) {
+ return !loopEffects.loopChangesLength(loop);
+ } else if (prim is GetField && !isImmutable(prim.field)) {
+ return !loopEffects.getSideEffectsInLoop(loop).changesInstanceProperty();
+ } else if (prim is GetStatic && !isImmutable(prim.element)) {
+ return !loopEffects.getSideEffectsInLoop(loop).changesStaticProperty();
+ } else if (prim is GetIndex) {
+ return !loopEffects.getSideEffectsInLoop(loop).changesIndex();
+ } else {
+ return true;
+ }
+ }
+
+
+ // ------------------ TRAVERSAL AND EFFECT NUMBERING ---------------------
+ //
+ // These methods traverse the IR while updating the current effect numbers.
+ // They are not specific to GVN.
+ //
+ // TODO(asgerf): Avoid duplicated code for side effect analysis.
+ // Should be easier to fix once primitives and call expressions are the same.
+
+ void addSideEffects(SideEffects fx, {bool length: true}) {
+ if (fx.changesInstanceProperty()) {
+ effectNumbers.instanceField = makeNewEffect();
+ }
+ if (fx.changesStaticProperty()) {
+ effectNumbers.staticField = makeNewEffect();
+ }
+ if (fx.changesIndex()) {
+ effectNumbers.indexableContent = makeNewEffect();
+ }
+ if (length && fx.changesIndex()) {
+ effectNumbers.indexableLength = makeNewEffect();
+ }
+ }
+
+ void addAllSideEffects() {
+ effectNumbers.instanceField = makeNewEffect();
+ effectNumbers.staticField = makeNewEffect();
+ effectNumbers.indexableContent = makeNewEffect();
+ effectNumbers.indexableLength = makeNewEffect();
+ }
+
+ Expression traverseLetHandler(LetHandler node) {
+ // Assume any kind of side effects may occur in the try block.
+ effectsAt[node.handler] = new EffectNumbers()
+ ..instanceField = makeNewEffect()
+ ..staticField = makeNewEffect()
+ ..indexableContent = makeNewEffect()
+ ..indexableLength = makeNewEffect();
+ push(node.handler);
+ return node.body;
+ }
+
+ Expression traverseContinuation(Continuation cont) {
+ Continuation oldLoopHeader = currentLoopHeader;
+ currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+ pushAction(() {
+ currentLoopHeader = oldLoopHeader;
+ });
+ for (Parameter param in cont.parameters) {
+ loopHeaderFor[param] = currentLoopHeader;
+ }
+ if (cont.isRecursive) {
+ addSideEffects(loopEffects.getSideEffectsInLoop(cont), length: false);
+ if (loopEffects.loopChangesLength(cont)) {
+ effectNumbers.indexableLength = makeNewEffect();
+ }
+ pushAction(() {
+ List<int> hoistedBindings = loopHoistedBindings[cont];
+ if (hoistedBindings != null) {
+ hoistedBindings.forEach(environment.remove);
+ }
+ });
+ } else {
+ EffectNumbers join = effectsAt[cont];
+ if (join != null) {
+ effectNumbers = join;
+ } else {
+ // This is a call continuation seen immediately after its use.
+ // Reuse the current effect numbers.
+ }
+ }
+
+ return cont.body;
+ }
+
+ void visitInvokeContinuation(InvokeContinuation node) {
+ Continuation cont = node.continuation.definition;
+ if (cont.isRecursive) return;
+ EffectNumbers join = effectsAt[cont];
+ if (join == null) {
+ effectsAt[cont] = effectNumbers.copy();
+ } else {
+ if (effectNumbers.instanceField != join.instanceField) {
+ join.instanceField = makeNewEffect();
+ }
+ if (effectNumbers.staticField != join.staticField) {
+ join.staticField = makeNewEffect();
+ }
+ if (effectNumbers.indexableContent != join.indexableContent) {
+ join.indexableContent = makeNewEffect();
+ }
+ if (effectNumbers.indexableLength != join.indexableLength) {
+ join.indexableLength = makeNewEffect();
+ }
+ }
+ }
+
+ void visitBranch(Branch node) {
+ Continuation trueCont = node.trueContinuation.definition;
+ Continuation falseCont = node.falseContinuation.definition;
+ // Copy the effect number vector once, so the analysis of one branch does
+ // not influence the other.
+ effectsAt[trueCont] = effectNumbers;
+ effectsAt[falseCont] = effectNumbers.copy();
+ }
+
+ void visitInvokeMethod(InvokeMethod node) {
+ addSideEffects(world.getSideEffectsOfSelector(node.selector, node.mask));
+ }
+
+ void visitInvokeStatic(InvokeStatic node) {
+ addSideEffects(world.getSideEffectsOfElement(node.target));
+ }
+
+ void visitInvokeMethodDirectly(InvokeMethodDirectly node) {
+ FunctionElement target = node.target;
+ if (target is ConstructorBodyElement) {
+ ConstructorBodyElement body = target;
+ target = body.constructor;
+ }
+ addSideEffects(world.getSideEffectsOfElement(target));
+ }
+
+ void visitInvokeConstructor(InvokeConstructor node) {
+ addSideEffects(world.getSideEffectsOfElement(node.target));
+ }
+
+ void visitSetStatic(SetStatic node) {
+ effectNumbers.staticField = makeNewEffect();
+ }
+
+ void visitSetField(SetField node) {
+ effectNumbers.instanceField = makeNewEffect();
+ }
+
+ void visitSetIndex(SetIndex node) {
+ effectNumbers.indexableContent = makeNewEffect();
+ }
+
+ void visitForeignCode(ForeignCode node) {
+ addSideEffects(node.nativeBehavior.sideEffects);
+ }
+
+ void visitGetLazyStatic(GetLazyStatic node) {
+ // TODO(asgerf): How do we get the side effects of a lazy field initializer?
+ addAllSideEffects();
+ }
+
+ void visitAwait(Await node) {
+ addAllSideEffects();
+ }
+
+ void visitYield(Yield node) {
+ addAllSideEffects();
+ }
+
+ void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
+ // Push and pop.
+ effectNumbers.indexableContent = makeNewEffect();
+ effectNumbers.indexableLength = makeNewEffect();
+ }
+}
+
+/// For each of the four categories of heap locations, the IR is divided into
+/// regions wherein the given heap locations are known not to be modified.
+///
+/// Each region is identified by its "effect number". Effect numbers from
+/// different categories have no relationship to each other.
+class EffectNumbers {
+ int indexableLength = 0;
+ int indexableContent = 0;
+ int staticField = 0;
+ int instanceField = 0;
+
+ EffectNumbers copy() {
+ return new EffectNumbers()
+ ..indexableLength = indexableLength
+ ..indexableContent = indexableContent
+ ..staticField = staticField
+ ..instanceField = instanceField;
+ }
+}
+
+/// Maps vectors to numbers, such that two vectors with the same contents
+/// map to the same number.
+class GvnTable {
+ Map<GvnEntry, int> _table = <GvnEntry, int>{};
+ int _usedGvns = 0;
+ int _makeNewGvn() => ++_usedGvns;
+
+ int insert(List vector) {
+ return _table.putIfAbsent(new GvnEntry(vector), _makeNewGvn);
+ }
+}
+
+/// Wrapper around a [List] that compares for equality based on contents
+/// instead of object identity.
+class GvnEntry {
+ final List vector;
+ final int hashCode;
+
+ GvnEntry(List vector) : vector = vector, hashCode = computeHashCode(vector);
+
+ bool operator==(other) {
+ if (other is! GvnEntry) return false;
+ GvnEntry entry = other;
+ List otherVector = entry.vector;
+ if (vector.length != otherVector.length) return false;
+ for (int i = 0; i < vector.length; ++i) {
+ if (vector[i] != otherVector[i]) return false;
+ }
+ return true;
+ }
+
+ /// Combines the hash codes of [vector] using Jenkin's hash function, with
+ /// intermediate results truncated to SMI range.
+ static int computeHashCode(List vector) {
+ int hash = 0;
+ for (int i = 0; i < vector.length; ++i) {
+ hash = 0x1fffffff & (hash + vector[i].hashCode);
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+ hash = hash ^ (hash >> 6);
+ }
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+ hash = hash ^ (hash >> 11);
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+ }
+}
+
+/// Converts GVN'able primitives to a vector containing all the values
+/// to be considered when computing a GVN for it.
+///
+/// This includes the instruction type, inputs, effect numbers for any part
+/// of the heap being depended on, as well as any instruction-specific payload
+/// such as any DartTypes, Elements, and operator kinds.
+///
+/// Each `visit` or `process` method for a primitive must initialize [vector]
+/// if the primitive is GVN'able and fill in any components except the inputs.
+/// The inputs will be filled in by [processReference].
+class GvnVectorBuilder extends DeepRecursiveVisitor {
+ List vector;
+ final Map<Primitive, int> gvnFor;
+ final JavaScriptBackend backend;
+ EffectNumbers effectNumbers;
+
+ GvnVectorBuilder(this.gvnFor, this.backend);
+
+ List make(Primitive prim, EffectNumbers effectNumbers) {
+ this.effectNumbers = effectNumbers;
+ vector = null;
+ visit(prim);
+ return vector;
+ }
+
+ /// The `process` methods below do not insert the referenced arguments into
+ /// the vector, but instead rely on them being inserted here.
+ processReference(Reference ref) {
+ if (vector == null) return;
+ Primitive prim = ref.definition.effectiveDefinition;
+ vector.add(gvnFor[prim] ?? prim);
+ }
+
+ processTypeTest(TypeTest node) {
+ vector = [GvnCode.TYPE_TEST, node.dartType];
+ }
+
+ processTypeTestViaFlag(TypeTestViaFlag node) {
+ vector = [GvnCode.TYPE_TEST_VIA_FLAG, node.dartType];
+ }
+
+ processApplyBuiltinOperator(ApplyBuiltinOperator node) {
+ vector = [GvnCode.BUILTIN_OPERATOR, node.operator.index];
+ }
+
+ processGetLength(GetLength node) {
+ // TODO(asgerf): Take fixed lengths into account?
+ vector = [GvnCode.GET_LENGTH, effectNumbers.indexableLength];
+ }
+
+ bool isImmutable(Element element) {
+ return element.isFunction ||
+ element.isField && (element.isFinal || element.isConst);
+ }
+
+ bool isNativeField(FieldElement field) {
+ // TODO(asgerf): We should add a GetNativeField instruction.
+ return backend.isNative(field);
+ }
+
+ processGetField(GetField node) {
+ if (isNativeField(node.field)) {
+ vector = null; // Native field access cannot be GVN'ed.
+ } else if (isImmutable(node.field)) {
+ vector = [GvnCode.GET_FIELD, node.field];
+ } else {
+ vector = [GvnCode.GET_FIELD, node.field, effectNumbers.instanceField];
+ }
+ }
+
+ processGetIndex(GetIndex node) {
+ vector = [GvnCode.GET_INDEX, effectNumbers.indexableContent];
+ }
+
+ processGetStatic(GetStatic node) {
+ if (isImmutable(node.element)) {
+ vector = [GvnCode.GET_STATIC, node.element];
+ } else {
+ vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
+ }
+ }
+
+ processGetLazyStatic(GetLazyStatic node) {
+ if (isImmutable(node.element)) {
+ vector = [GvnCode.GET_STATIC, node.element];
+ } else {
+ vector = [GvnCode.GET_STATIC, node.element, effectNumbers.staticField];
+ }
+ }
+
+ processConstant(Constant node) {
+ vector = [GvnCode.CONSTANT, node.value];
+ }
+
+ processReifyRuntimeType(ReifyRuntimeType node) {
+ vector = [GvnCode.REIFY_RUNTIME_TYPE];
+ }
+
+ processReadTypeVariable(ReadTypeVariable node) {
+ vector = [GvnCode.READ_TYPE_VARIABLE, node.variable];
+ }
+
+ processTypeExpression(TypeExpression node) {
+ vector = [GvnCode.TYPE_EXPRESSION, node.dartType];
+ }
+
+ processInterceptor(Interceptor node) {
+ vector = [GvnCode.INTERCEPTOR];
+ }
+}
+
+class GvnCode {
+ static const int TYPE_TEST = 1;
+ static const int TYPE_TEST_VIA_FLAG = 2;
+ static const int BUILTIN_OPERATOR = 3;
+ static const int GET_LENGTH = 4;
+ static const int GET_FIELD = 5;
+ static const int GET_INDEX = 6;
+ static const int GET_STATIC = 7;
+ static const int CONSTANT = 8;
+ static const int REIFY_RUNTIME_TYPE = 9;
+ static const int READ_TYPE_VARIABLE = 10;
+ static const int TYPE_EXPRESSION = 11;
+ static const int INTERCEPTOR = 12;
+}
+
+typedef ReferenceCallback(Reference ref);
+class InputVisitor extends DeepRecursiveVisitor {
+ ReferenceCallback callback;
+
+ InputVisitor(this.callback);
+
+ @override
+ processReference(Reference ref) {
+ callback(ref);
+ }
+
+ static void forEach(Primitive node, ReferenceCallback callback) {
+ new InputVisitor(callback).visit(node);
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
index 6c5ec70..66fe170 100644
--- a/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/insert_refinements.dart
@@ -75,11 +75,15 @@
return prim is Interceptor ? prim.input.definition : prim;
}
- /// Enqueues [cont] for processing in a context where [refined] is the
- /// current refinement for its value.
- void pushRefinement(Continuation cont, Refinement refined) {
+ /// Sets [refined] to be the current refinement for its value, and pushes an
+ /// action that will restore the original scope again.
+ ///
+ /// The refinement is inserted as the child of [insertionParent] if it has
+ /// at least one use after its scope has been processed.
+ void applyRefinement(InteriorNode insertionParent, Refinement refined) {
Primitive value = refined.effectiveDefinition;
Primitive currentRefinement = refinementFor[value];
+ refinementFor[value] = refined;
pushAction(() {
refinementFor[value] = currentRefinement;
if (refined.hasNoUses) {
@@ -87,18 +91,21 @@
refined.destroy();
} else {
LetPrim let = new LetPrim(refined);
- let.insertBelow(cont);
+ let.insertBelow(insertionParent);
}
});
- push(cont);
+ }
+
+ /// Enqueues [cont] for processing in a context where [refined] is the
+ /// current refinement for its value.
+ void pushRefinement(Continuation cont, Refinement refined) {
pushAction(() {
- refinementFor[value] = refined;
+ applyRefinement(cont, refined);
+ push(cont);
});
}
void visitInvokeMethod(InvokeMethod node) {
- Continuation cont = node.continuation.definition;
-
// Update references to their current refined values.
processReference(node.receiver);
node.arguments.forEach(processReference);
@@ -107,34 +114,28 @@
// not the interceptor.
Primitive receiver = unfoldInterceptor(node.receiver.definition);
- // Sink the continuation to the call to ensure everything in scope
- // here is also in scope inside the continuations.
- sinkContinuationToUse(cont, node);
-
- if (node.selector.isClosureCall) {
- // Do not try to refine the receiver of closure calls; the class world
- // does not know about closure classes.
- push(cont);
- } else {
+ // Do not try to refine the receiver of closure calls; the class world
+ // does not know about closure classes.
+ if (!node.selector.isClosureCall) {
// Filter away receivers that throw on this selector.
TypeMask type = types.receiverTypeFor(node.selector, node.mask);
Refinement refinement = new Refinement(receiver, type);
- pushRefinement(cont, refinement);
+ LetPrim letPrim = node.parent;
+ applyRefinement(letPrim, refinement);
}
}
void visitTypeCast(TypeCast node) {
- Continuation cont = node.continuation.definition;
Primitive value = node.value.definition;
processReference(node.value);
node.typeArguments.forEach(processReference);
// Refine the type of the input.
- sinkContinuationToUse(cont, node);
TypeMask type = types.subtypesOf(node.dartType).nullable();
Refinement refinement = new Refinement(value, type);
- pushRefinement(cont, refinement);
+ LetPrim letPrim = node.parent;
+ applyRefinement(letPrim, refinement);
}
void visitRefinement(Refinement node) {
@@ -151,16 +152,6 @@
});
}
- CallExpression getCallWithResult(Primitive prim) {
- if (prim is Parameter && prim.parent is Continuation) {
- Continuation cont = prim.parent;
- if (cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression) {
- return cont.firstRef.parent;
- }
- }
- return null;
- }
-
bool isTrue(Primitive prim) {
return prim is Constant && prim.value.isTrue;
}
@@ -168,7 +159,6 @@
void visitBranch(Branch node) {
processReference(node.condition);
Primitive condition = node.condition.definition;
- CallExpression call = getCallWithResult(condition);
Continuation trueCont = node.trueContinuation.definition;
Continuation falseCont = node.falseContinuation.definition;
@@ -212,9 +202,9 @@
}
}
- if (call is InvokeMethod && call.selector == Selectors.equals) {
- refineEquality(call.arguments[0].definition,
- call.arguments[1].definition,
+ if (condition is InvokeMethod && condition.selector == Selectors.equals) {
+ refineEquality(condition.dartReceiver,
+ condition.dartArgument(0),
trueCont,
falseCont);
return;
@@ -236,13 +226,8 @@
@override
Expression traverseLetCont(LetCont node) {
for (Continuation cont in node.continuations) {
- if (cont.hasExactlyOneUse &&
- (cont.firstRef.parent is InvokeMethod ||
- cont.firstRef.parent is TypeCast ||
- cont.firstRef.parent is Branch)) {
- // Do not push the continuation here.
- // visitInvokeMethod, visitBranch, and visitTypeCast will do that.
- } else {
+ // Do not push the branch continuations here. visitBranch will do that.
+ if (!(cont.hasExactlyOneUse && cont.firstRef.parent is Branch)) {
push(cont);
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_effects.dart b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
index 9dd39ff..6679336 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_effects.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_effects.dart
@@ -46,9 +46,7 @@
Expression traverseContinuation(Continuation cont) {
if (cont.isRecursive) {
SideEffects oldEffects = currentLoopSideEffects;
- Continuation oldLoopHeader = currentLoopHeader;
bool oldChangesLength = currentLoopChangesLength;
- currentLoopHeader = cont;
loopSideEffects[cont] = currentLoopSideEffects = new SideEffects.empty();
exitContinuations[cont] = <Continuation>[];
pushAction(() {
@@ -57,11 +55,15 @@
loopsChangingLength.add(cont);
}
currentLoopChangesLength = currentLoopChangesLength || oldChangesLength;
- currentLoopHeader = oldLoopHeader;
currentLoopSideEffects = oldEffects;
exitContinuations[cont].forEach(push);
});
}
+ Continuation oldLoopHeader = currentLoopHeader;
+ currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+ pushAction(() {
+ currentLoopHeader = oldLoopHeader;
+ });
return cont.body;
}
@@ -87,6 +89,13 @@
Continuation inner = currentLoopHeader;
Continuation outer = loopHierarchy.getEnclosingLoop(currentLoopHeader);
while (outer != loop) {
+ if (inner == null) {
+ // The shrinking reductions pass must run before any pass that relies
+ // on computing loop side effects.
+ world.compiler.reporter.internalError(null,
+ 'Unreachable continuations must be removed before computing '
+ 'loop side effects.');
+ }
inner = outer;
outer = loopHierarchy.getEnclosingLoop(outer);
}
@@ -171,6 +180,7 @@
}
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
+ currentLoopSideEffects.setChangesIndex();
currentLoopChangesLength = true; // Push and pop.
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
index 3aa5bc9..99b1105 100644
--- a/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
+++ b/pkg/compiler/lib/src/cps_ir/loop_hierarchy.dart
@@ -99,29 +99,13 @@
return loopTarget[cont];
}
- bool _isCallContinuation(Continuation cont) {
- return cont.hasExactlyOneUse && cont.firstRef.parent is CallExpression;
- }
-
/// Analyzes a basic block and returns the innermost loop that
/// can be invoked recursively from that block.
Continuation _processBlock(Expression node, Continuation catchLoop) {
- List<Continuation> callContinuations = <Continuation>[];
for (; node is! TailExpression; node = node.next) {
if (node is LetCont) {
for (Continuation cont in node.continuations) {
- if (!_isCallContinuation(cont)) {
- // Process non-call continuations at the binding site, so they
- // their loop target is known at all use sites.
- _processContinuation(cont, catchLoop);
- } else {
- // To avoid deep recursion, do not analyze call continuations
- // recursively. This basic block traversal steps into the
- // call contiunation after visiting its use site. We store the
- // continuations in a list so we can set the loop target once
- // it is known.
- callContinuations.add(cont);
- }
+ _processContinuation(cont, catchLoop);
}
} else if (node is LetHandler) {
catchLoop = _processContinuation(node.handler, catchLoop);
@@ -141,13 +125,28 @@
} else {
assert(node is Unreachable || node is Throw);
}
- target = _markInnerLoop(target, catchLoop);
- for (Continuation cont in callContinuations) {
- // Store the loop target on each call continuation in the basic block.
- // Because we walk over call continuations as part of the basic block
- // traversal, these do not get their loop target set otherwise.
- loopTarget[cont] = target;
+ return _markInnerLoop(target, catchLoop);
+ }
+
+ /// Returns the the innermost loop that effectively encloses both
+ /// c1 and c2 (or `null` if there is no such loop).
+ Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
+ int d1 = getDepth(c1), d2 = getDepth(c2);
+ while (c1 != c2) {
+ if (d1 <= d2) {
+ c2 = getEnclosingLoop(c2);
+ d2 = getDepth(c2);
+ } else {
+ c1 = getEnclosingLoop(c1);
+ d1 = getDepth(c1);
+ }
}
- return target;
+ return c1;
+ }
+
+ /// Returns the lexical nesting depth of [loop].
+ int getDepth(Continuation loop) {
+ if (loop == null) return 0;
+ return loopDepth[loop];
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
index d4630b5..e5ea7a8 100644
--- a/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
+++ b/pkg/compiler/lib/src/cps_ir/mutable_ssa.dart
@@ -168,7 +168,7 @@
if (shouldRewrite(variable)) {
// Replace with the reaching definition from the environment.
Primitive value = environment[variable];
- value.substituteFor(getter);
+ getter.replaceUsesWith(value);
mergeHints(variable, value);
node.remove();
}
diff --git a/pkg/compiler/lib/src/cps_ir/octagon.dart b/pkg/compiler/lib/src/cps_ir/octagon.dart
index 8dfd5f1..691c15d 100644
--- a/pkg/compiler/lib/src/cps_ir/octagon.dart
+++ b/pkg/compiler/lib/src/cps_ir/octagon.dart
@@ -4,6 +4,8 @@
library dart2js.cps_ir.octagon;
+import 'dart:collection';
+
/// For every variable in the constraint system, two [SignedVariable]s exist,
/// representing the positive and negative uses of the variable.
///
@@ -20,9 +22,6 @@
static int _hashCount = 0;
final int hashCode = (_hashCount = _hashCount + 1) & 0x0fffffff;
- /// Temporary field used by the constraint solver's graph search.
- bool _isBeingVisited = false;
-
SignedVariable._make() {
_negated = new SignedVariable._makeTwin(this);
}
@@ -87,17 +86,14 @@
///
/// The constraint should be removed again using [popConstraint].
void pushConstraint(Constraint constraint) {
- if (_unsolvableCounter > 0) {
+ if (_unsolvableCounter > 0 ||
+ _unsolvableCounter == 0 && _checkUnsolvable(constraint)) {
++_unsolvableCounter;
}
constraint.v1._constraints.add(constraint);
if (constraint.v1 != constraint.v2) {
constraint.v2._constraints.add(constraint);
}
- // Check if this constraint has made the system unsolvable.
- if (_unsolvableCounter == 0 && _checkUnsolvable(constraint)) {
- _unsolvableCounter = 1;
- }
}
/// Remove a constraint that was previously added with [pushConstraint].
@@ -115,101 +111,87 @@
}
}
- // Temporaries using during path finding.
- SignedVariable _goal;
- Map<SignedVariable, int> _distanceToGoal;
-
- /// Return true if the recently added [constraint] made the system unsolvable.
+ /// Return true if [constraint] would make the constraint system unsolvable.
///
- /// This function assumes the system was solvable before adding [constraint].
+ /// Assumes the system is currently solvable.
bool _checkUnsolvable(Constraint constraint) {
// Constraints are transitively composed like so:
- // v1 - v2 <= k1
- // v2 - v3 <= k2
+ // v1 + v2 <= k1
+ // -v2 + v3 <= k2
// implies:
- // v1 - v3 <= k1 + k2
+ // v1 + v3 <= k1 + k2
//
- // We construct a graph such that the tightest bound on `v1 - v3` is the
- // weight of the shortest path from `v1` to `v3`.
+ // We construct a graph such that the tightest bound on `v1 + v3` is the
+ // weight of the shortest path from `v1` to `-v3`.
//
- // Ever constraint `v1 - v2 <= k` gives rise to two edges:
- // (v1) --k--> (v2)
- // (-v2) --k--> (-v2)
+ // Every constraint `v1 + v2 <= k` gives rise to two edges:
+ // (v1) --k--> (-v2)
+ // (v2) --k--> (-v1)
//
// The system is unsolvable if and only if a negative-weight cycle exists
// in this graph (this corresponds to a variable being less than itself).
- // We assume the system was solvable to begin with, so we only look for
- // cycles that use the new edges.
- //
- // The new [constraint] `v1 + v2 <= k` just added the edges:
- // (v1) --k--> (-v2)
- // (v2) --k--> (-v1)
- //
- // Look for a path from (-v2) to (v1) with weight at most -k-1, as this
- // will complete a negative-weight cycle.
-
- // It suffices to do this once. We need not check for the converse path
- // (-v1) to (v2) because of the symmetry in the graph.
- //
- // Note that the graph symmetry is not a redundancy. Some cycles include
- // both of the new edges at once, so they must be added to the graph
- // beforehand.
- _goal = constraint.v2;
- _distanceToGoal = <SignedVariable, int>{};
- int targetWeight = -constraint.bound - 1;
- int pathWeight = _search(constraint.v1.negated, targetWeight, 0);
- return pathWeight != null && pathWeight <= targetWeight;
+ // Check if a negative-weight cycle would be created by adding [constraint].
+ int length = _cycleLength(constraint);
+ return length != null && length < 0;
}
- static const int MAX_DEPTH = 100;
-
- /// Returns the shortest path from [v1] to [_goal] (or any path shorter than
- /// [budget]), or `null` if no path exists.
- int _search(SignedVariable v1, int budget, int depth) {
- if (v1 == _goal && budget >= 0) return 0;
-
- // Disregard paths that use a lot of edges.
- // In extreme cases (e.g. hundreds of `push` calls or nested ifs) this can
- // get slow and/or overflow the stack. Most paths that matter are very
- // short (1-5 edges) with some occasional 10-30 length paths in math code.
- if (depth >= MAX_DEPTH) return null;
-
- // We found a cycle, but not the one we're looking for. If the constraint
- // system was solvable to being with, then this must be a positive-weight
- // cycle, and no shortest path goes through a positive-weight cycle.
- if (v1._isBeingVisited) return null;
-
- // Check if we have previously searched from here.
- if (_distanceToGoal.containsKey(v1)) {
- // We have already searched this node, return the cached answer.
- // Note that variables may explicitly map to null, so the double lookup
- // is necessary.
- return _distanceToGoal[v1];
+ /// Returns the length of the shortest simple cycle that would be created by
+ /// adding [constraint] to the graph.
+ ///
+ /// Assumes there are no existing negative-weight cycles. The new cycle
+ /// may have negative weight as [constraint] has not been added yet.
+ int _cycleLength(Constraint constraint) {
+ // Single-source shortest path using a FIFO queue.
+ Queue<SignedVariable> worklist = new Queue<SignedVariable>();
+ Map<SignedVariable, int> distance = {};
+ void updateDistance(SignedVariable v, int newDistance) {
+ int oldDistance = distance[v];
+ if (oldDistance == null || oldDistance > newDistance) {
+ distance[v] = newDistance;
+ worklist.addLast(v);
+ }
}
-
- v1._isBeingVisited = true;
-
- int shortestDistance = v1 == _goal ? 0 : null;
- for (Constraint c in v1._constraints) {
- SignedVariable v2 = c.v1 == v1 ? c.v2 : c.v1;
- int distance = _search(v2.negated, budget - c.bound, depth + 1);
- if (distance != null) {
- distance += c.bound; // Pay the cost of using the edge.
- if (distance <= budget) {
- // Success! We found a path that is short enough so return fast.
- // All recursive calls will now return immediately, so there is no
- // need to update distanceToGoal, but we need to clear the
- // beingVisited flag for the next query.
- v1._isBeingVisited = false;
- return distance;
- } else if (shortestDistance == null || distance < shortestDistance) {
- shortestDistance = distance;
+ void iterateWorklist() {
+ while (!worklist.isEmpty) {
+ SignedVariable v1 = worklist.removeFirst();
+ int distanceToV1 = distance[v1];
+ for (Constraint c in v1._constraints) {
+ SignedVariable v2 = c.v1 == v1 ? c.v2 : c.v1;
+ updateDistance(v2.negated, distanceToV1 + c.bound);
}
}
}
- v1._isBeingVisited = false;
- _distanceToGoal[v1] = shortestDistance;
- return shortestDistance;
+ // Two new edges will be added by the constraint `v1 + v2 <= k`:
+ //
+ // A. (v1) --> (-v2)
+ // B. (v2) --> (-v1)
+ //
+ // We need to check for two kinds of cycles:
+ //
+ // Using only A: (-v2) --> (v1) --A--> (-v2)
+ // Using B and then A: (-v2) --> (v2) --B--> (-v1) --> (v1) --A--> (-v2)
+ //
+ // Because of the graph symmetry, cycles using only B or using A and then B
+ // exist if and only if the corresponding cycle above exist, so there is no
+ // need to check for those.
+ //
+ // Do a single-source shortest paths reaching out from (-v2).
+ updateDistance(constraint.v2.negated, 0);
+ iterateWorklist();
+ if (constraint.v1 != constraint.v2) {
+ int distanceToV2 = distance[constraint.v2];
+ if (distanceToV2 != null) {
+ // Allow one use of the B edge.
+ // This must be done outside fixpoint iteration as an infinite loop
+ // would arise when an negative-weight cycle using only B exists.
+ updateDistance(constraint.v1.negated, distanceToV2 + constraint.bound);
+ iterateWorklist();
+ }
+ }
+ // Get the distance to (v1) and check if the A edge would complete a cycle.
+ int distanceToV1 = distance[constraint.v1];
+ if (distanceToV1 == null) return null;
+ return distanceToV1 + constraint.bound;
}
}
diff --git a/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
new file mode 100644
index 0000000..599989a
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/optimize_interceptors.dart
@@ -0,0 +1,187 @@
+// 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 dart2js.cps_ir.optimize_interceptors;
+
+import 'optimizers.dart';
+import 'cps_ir_nodes.dart';
+import 'loop_hierarchy.dart';
+import 'cps_fragment.dart';
+import '../constants/values.dart';
+import '../elements/elements.dart';
+import '../js_backend/backend_helpers.dart' show BackendHelpers;
+import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/types.dart' show TypeMask;
+import '../io/source_information.dart' show SourceInformation;
+
+/// Replaces `getInterceptor` calls with interceptor constants when possible,
+/// or with "almost constant" expressions like "x && CONST" when the input
+/// is either null or has a known interceptor.
+//
+// TODO(asgerf): Compute intercepted classes in this pass.
+class OptimizeInterceptors extends TrampolineRecursiveVisitor implements Pass {
+ String get passName => 'Optimize interceptors';
+
+ JavaScriptBackend backend;
+ LoopHierarchy loopHierarchy;
+ Continuation currentLoopHeader;
+
+ OptimizeInterceptors(this.backend);
+
+ BackendHelpers get helpers => backend.helpers;
+
+ void rewrite(FunctionDefinition node) {
+ // TODO(asgerf): Computing the LoopHierarchy here may be overkill when all
+ // we want is to hoist constants out of loops.
+ loopHierarchy = new LoopHierarchy(node);
+ visit(node.body);
+ new ShareConstants().visit(node);
+ }
+
+ @override
+ Expression traverseContinuation(Continuation cont) {
+ Continuation oldLoopHeader = currentLoopHeader;
+ currentLoopHeader = loopHierarchy.getLoopHeader(cont);
+ pushAction(() {
+ currentLoopHeader = oldLoopHeader;
+ });
+ return cont.body;
+ }
+
+ /// If only one method table can be returned by the given interceptor,
+ /// returns a constant for that method table.
+ InterceptorConstantValue getInterceptorConstant(Interceptor node) {
+ if (node.interceptedClasses.length == 1 &&
+ node.isInterceptedClassAlwaysExact) {
+ ClassElement interceptorClass = node.interceptedClasses.single;
+ return new InterceptorConstantValue(interceptorClass.rawType);
+ }
+ return null;
+ }
+
+ bool hasNoFalsyValues(ClassElement class_) {
+ return class_ != helpers.jsInterceptorClass &&
+ class_ != helpers.jsNullClass &&
+ class_ != helpers.jsBoolClass &&
+ class_ != helpers.jsStringClass &&
+ !class_.isSubclassOf(helpers.jsNumberClass);
+ }
+
+ Continuation getCurrentOuterLoop({Continuation scope}) {
+ Continuation inner = null, outer = currentLoopHeader;
+ while (outer != scope) {
+ inner = outer;
+ outer = loopHierarchy.getEnclosingLoop(outer);
+ }
+ return inner;
+ }
+
+ /// Binds the given constant in a primitive, in scope of the [useSite].
+ ///
+ /// The constant will be hoisted out of loops, and shared with other requests
+ /// for the same constant as long as it is in scope.
+ Primitive makeConstantFor(ConstantValue constant,
+ {Expression useSite,
+ TypeMask type,
+ SourceInformation sourceInformation,
+ Entity hint}) {
+ Constant prim =
+ new Constant(constant, sourceInformation: sourceInformation);
+ prim.hint = hint;
+ prim.type = type;
+ LetPrim letPrim = new LetPrim(prim);
+ Continuation loop = getCurrentOuterLoop();
+ if (loop != null) {
+ LetCont loopBinding = loop.parent;
+ letPrim.insertAbove(loopBinding);
+ } else {
+ letPrim.insertAbove(useSite);
+ }
+ return prim;
+ }
+
+ void constifyInterceptor(Interceptor interceptor) {
+ LetPrim let = interceptor.parent;
+ InterceptorConstantValue constant = getInterceptorConstant(interceptor);
+
+ if (constant == null) return;
+
+ if (interceptor.isAlwaysIntercepted) {
+ Primitive constantPrim = makeConstantFor(constant,
+ useSite: let,
+ type: interceptor.type,
+ sourceInformation: interceptor.sourceInformation);
+ constantPrim.useElementAsHint(interceptor.hint);
+ interceptor..replaceUsesWith(constantPrim)..destroy();
+ let.remove();
+ } else if (interceptor.isAlwaysNullOrIntercepted) {
+ Primitive input = interceptor.input.definition;
+ Primitive constantPrim = makeConstantFor(constant,
+ useSite: let,
+ type: interceptor.type.nonNullable(),
+ sourceInformation: interceptor.sourceInformation);
+ CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
+ Parameter param = new Parameter(interceptor.hint);
+ Continuation cont = cps.letCont(<Parameter>[param]);
+ if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
+ // If null is the only falsy value, compile as "x && CONST".
+ cps.ifFalsy(input).invokeContinuation(cont, [input]);
+ } else {
+ // If there are other falsy values compile as "x == null ? x : CONST".
+ Primitive condition = cps.applyBuiltin(
+ BuiltinOperator.LooseEq,
+ [input, cps.makeNull()]);
+ cps.ifTruthy(condition).invokeContinuation(cont, [input]);
+ }
+ cps.invokeContinuation(cont, [constantPrim]);
+ cps.context = cont;
+ cps.insertAbove(let);
+ interceptor..replaceUsesWith(param)..destroy();
+ let.remove();
+ }
+ }
+
+ @override
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ if (node.primitive is Interceptor) {
+ constifyInterceptor(node.primitive);
+ }
+ return next;
+ }
+}
+
+/// Shares interceptor constants when one is in scope of another.
+///
+/// Interceptor optimization runs after GVN, hence this clean-up step is needed.
+///
+/// TODO(asgerf): Handle in separate constant optimization pass? With some other
+/// constant-related optimizations, like cloning small constants at use-site.
+class ShareConstants extends TrampolineRecursiveVisitor {
+ Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
+
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
+ Constant prim = node.primitive;
+ Constant existing = sharedConstantFor[prim.value];
+ if (existing != null) {
+ existing.useElementAsHint(prim.hint);
+ prim..replaceUsesWith(existing)..destroy();
+ node.remove();
+ return next;
+ }
+ sharedConstantFor[prim.value] = prim;
+ pushAction(() {
+ assert(sharedConstantFor[prim.value] == prim);
+ sharedConstantFor.remove(prim.value);
+ });
+ }
+ return next;
+ }
+
+ bool shouldShareConstant(Constant constant) {
+ return constant.value.isInterceptor;
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/optimizers.dart b/pkg/compiler/lib/src/cps_ir/optimizers.dart
index 37e8b3c..9d5f13e 100644
--- a/pkg/compiler/lib/src/cps_ir/optimizers.dart
+++ b/pkg/compiler/lib/src/cps_ir/optimizers.dart
@@ -15,9 +15,10 @@
export 'mutable_ssa.dart' show MutableVariableEliminator;
export 'insert_refinements.dart' show InsertRefinements;
export 'remove_refinements.dart' show RemoveRefinements;
-export 'share_final_fields.dart' show ShareFinalFields;
-export 'share_interceptors.dart' show ShareInterceptors;
+export 'redundant_refinement.dart' show RedundantRefinementEliminator;
+export 'optimize_interceptors.dart' show OptimizeInterceptors;
export 'bounds_checker.dart' show BoundsChecker;
+export 'gvn.dart' show GVN;
export 'parent_visitor.dart' show ParentVisitor;
/// An optimization pass over the CPS IR.
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
index 183f8e3..7f16af9 100644
--- a/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
+++ b/pkg/compiler/lib/src/cps_ir/redundant_phi.dart
@@ -138,7 +138,7 @@
// * and implicitly remove param from continuation signature and
// invocations by not incrementing `dst`. References of removed
// arguments are unlinked to keep definition usages up to date.
- uniqueDefinition.substituteFor(oldDefinition);
+ oldDefinition.replaceUsesWith(uniqueDefinition);
for (InvokeContinuation invoke in invokes) {
invoke.arguments[src].unlink();
}
@@ -191,7 +191,7 @@
/// Ensures [continuation] has its own LetCont binding by creating
/// a new LetCont below its current binding, if necessary.
-///
+///
/// Returns the LetCont that now binds [continuation].
LetCont _makeUniqueBinding(Continuation continuation) {
LetCont letCont = continuation.parent;
diff --git a/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart b/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
new file mode 100644
index 0000000..cff47d6
--- /dev/null
+++ b/pkg/compiler/lib/src/cps_ir/redundant_refinement.dart
@@ -0,0 +1,55 @@
+// 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 dart2js.cps_ir.redundant_refinement;
+
+import 'cps_ir_nodes.dart';
+import 'optimizers.dart' show Pass;
+import 'type_mask_system.dart';
+
+/// Removes [Refinement] nodes where the input value is already known to
+/// satisfy the refinement type.
+///
+/// Note: This pass improves loop-invariant code motion in the GVN pass because
+/// GVN will currently not hoist a primitive across a refinement guard.
+/// But some opportunities for hoisting are still missed. A field access can
+/// safely be hoisted across a non-redundant refinement as long as the less
+/// refined value is still known to have the field. For example:
+///
+/// class A { var field; }
+/// class B extends A {}
+///
+/// var x = getA(); // Return type is subclass of A.
+/// while (x is B) { // Refinement to B is not redundant.
+/// x.field.baz++; // x.field is safe for hoisting,
+/// } // but blocked by the refinement node.
+///
+/// Ideally, this pass should go away and GVN should handle refinements
+/// directly.
+class RedundantRefinementEliminator extends TrampolineRecursiveVisitor
+ implements Pass {
+ String get passName => 'Redundant refinement elimination';
+
+ TypeMaskSystem typeSystem;
+
+ RedundantRefinementEliminator(this.typeSystem);
+
+ void rewrite(FunctionDefinition node) {
+ visit(node);
+ }
+
+ Expression traverseLetPrim(LetPrim node) {
+ Expression next = node.body;
+ if (node.primitive is Refinement) {
+ Refinement refinement = node.primitive;
+ Primitive value = refinement.value.definition;
+ if (typeSystem.isMorePreciseOrEqual(value.type, refinement.refineType)) {
+ refinement..replaceUsesWith(value)..destroy();
+ node.remove();
+ return next;
+ }
+ }
+ return next;
+ }
+}
diff --git a/pkg/compiler/lib/src/cps_ir/remove_refinements.dart b/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
index 2d49c95..eead3f0 100644
--- a/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
+++ b/pkg/compiler/lib/src/cps_ir/remove_refinements.dart
@@ -27,8 +27,7 @@
if (refinement.hint != null && value.hint == null) {
value.hint = refinement.hint;
}
- value.substituteFor(refinement);
- refinement.destroy();
+ refinement..replaceUsesWith(value)..destroy();
node.remove();
}
return next;
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index 9d5ce4f..b220847 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -142,12 +142,12 @@
GetMutable getter = new GetMutable(variable);
getter.type = getField.type;
getter.variable.parent = getter;
- getter.substituteFor(getField);
+ getField.replaceUsesWith(getter);
replacePrimitive(getField, getter);
deletePrimitive(getField);
} else {
Primitive value = fieldInitialValues[getField.field];
- value.substituteFor(getField);
+ getField.replaceUsesWith(value);
deleteLetPrimOf(getField);
}
} else if (use is SetField && use.object == ref) {
@@ -158,7 +158,7 @@
SetMutable setter = new SetMutable(variable, value);
setter.variable.parent = setter;
setter.value.parent = setter;
- setter.substituteFor(setField);
+ setField.replaceUsesWith(setter);
replacePrimitive(setField, setter);
deletePrimitive(setField);
} else {
diff --git a/pkg/compiler/lib/src/cps_ir/share_final_fields.dart b/pkg/compiler/lib/src/cps_ir/share_final_fields.dart
deleted file mode 100644
index 3308c00..0000000
--- a/pkg/compiler/lib/src/cps_ir/share_final_fields.dart
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.cps_ir.share_final_fields;
-
-import 'optimizers.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import '../elements/elements.dart';
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-
-/// Removes redundant GetField operations.
-///
-/// The pass performs these optimizations for field loads:
-/// - share GetFields of final fields when one is in scope of the other.
-/// - pull GetField operations of final fields out of loops when safe (object is
-/// not null).
-///
-/// This pass only optimizes final fields and should be replaced with a full
-/// load elimination pass.
-class ShareFinalFields extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Share final fields';
-
- /// The innermost loop containing a given primitive.
- final Map<Primitive, Continuation> loopHeaderFor =
- <Primitive, Continuation>{};
-
- // field -> receiver -> GetField
- Map<FieldElement, Map<Primitive, Primitive>> fieldValues =
- <FieldElement, Map<Primitive, Primitive>>{};
-
- /// Interceptors that have been hoisted out of a given loop.
- final Map<Continuation, List<GetField>> loopHoistedGetters =
- <Continuation, List<GetField>>{};
-
- JavaScriptBackend backend;
- LoopHierarchy loopHierarchy;
- Continuation currentLoopHeader;
-
- ShareFinalFields(this.backend);
-
- void rewrite(FunctionDefinition node) {
- loopHierarchy = new LoopHierarchy(node);
- visit(node.body);
- }
-
- @override
- Expression traverseContinuation(Continuation cont) {
- Continuation oldLoopHeader = currentLoopHeader;
- currentLoopHeader = loopHierarchy.getLoopHeader(cont);
- for (Parameter parameter in cont.parameters) {
- loopHeaderFor[parameter] = currentLoopHeader;
- }
- if (cont.isRecursive) {
- pushAction(() {
- // After the loop body has been processed, all values hoisted to this
- // loop fall out of scope and should be removed from the environment.
- List<GetField> hoisted = loopHoistedGetters[cont];
- if (hoisted != null) {
- for (GetField primitive in hoisted) {
- Primitive refinedReceiver = primitive.object.definition;
- Primitive receiver = refinedReceiver.effectiveDefinition;
- var map = fieldValues[primitive.field];
- assert(map[receiver] == primitive);
- map.remove(receiver);
- }
- }
- });
- }
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
- return cont.body;
- }
-
- Continuation getCurrentOuterLoop({Continuation scope}) {
- Continuation inner = null, outer = currentLoopHeader;
- while (outer != scope) {
- inner = outer;
- outer = loopHierarchy.getEnclosingLoop(outer);
- }
- return inner;
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- loopHeaderFor[node.primitive] = currentLoopHeader;
- Expression next = node.body;
- if (node.primitive is! GetField) {
- return next;
- }
- GetField primitive = node.primitive;
- FieldElement field = primitive.field;
-
- if (!shouldShareField(field)) {
- return next;
- }
-
- Primitive refinedReceiver = primitive.object.definition;
- Primitive receiver = refinedReceiver.effectiveDefinition;
-
- // Try to reuse an existing load for the same input.
- var map = fieldValues.putIfAbsent(field, () => <Primitive,Primitive>{});
- Primitive existing = map[receiver];
- if (existing != null) {
- existing.substituteFor(primitive);
- primitive.destroy();
- node.remove();
- return next;
- }
-
- map[receiver] = primitive;
-
- if (primitive.objectIsNotNull) {
- // Determine how far the GetField can be lifted. The outermost loop that
- // contains the input binding should also contain the load.
- // Don't move above a refinement guard since that might be unsafe.
-
- // TODO(sra): We can move above a refinement guard provided the input is
- // still in scope and safe (non-null). We will have to replace
- // primitive.object with the most constrained refinement still in scope.
- Continuation referencedLoop =
- lowestCommonAncestor(loopHeaderFor[refinedReceiver],
- currentLoopHeader);
- if (referencedLoop != currentLoopHeader) {
- Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
- LetCont loopBinding = hoistTarget.parent;
- node.remove();
- node.insertAbove(loopBinding);
- // Remove the hoisted operations from the environment after processing
- // the loop.
- loopHoistedGetters
- .putIfAbsent(hoistTarget, () => <GetField>[])
- .add(primitive);
- return next;
- }
- }
-
- pushAction(() {
- var map = fieldValues[field];
- assert(map[receiver] == primitive);
- map.remove(receiver);
- });
- return next;
- }
-
- bool shouldShareField(FieldElement field) {
- // TODO(24781): This query is incorrect for fields assigned only via
- //
- // super.field = ...
- //
- // return backend.compiler.world.fieldNeverChanges(field);
-
- // Native fields are getters with side effects (e.g. layout).
- if (backend.isNative(field)) return false;
- return field.isFinal || field.isConst;
- }
-
- /// Returns the the innermost loop that effectively encloses both
- /// c1 and c2 (or `null` if there is no such loop).
- Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
- int d1 = getDepth(c1), d2 = getDepth(c2);
- while (c1 != c2) {
- if (d1 <= d2) {
- c2 = loopHierarchy.getEnclosingLoop(c2);
- d2 = getDepth(c2);
- } else {
- c1 = loopHierarchy.getEnclosingLoop(c1);
- d1 = getDepth(c1);
- }
- }
- return c1;
- }
-
- int getDepth(Continuation loop) {
- if (loop == null) return -1;
- return loopHierarchy.loopDepth[loop];
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart b/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
deleted file mode 100644
index 1fbbba3..0000000
--- a/pkg/compiler/lib/src/cps_ir/share_interceptors.dart
+++ /dev/null
@@ -1,278 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library dart2js.cps_ir.share_interceptors;
-
-import 'optimizers.dart';
-import 'cps_ir_nodes.dart';
-import 'loop_hierarchy.dart';
-import 'cps_fragment.dart';
-import '../constants/values.dart';
-import '../elements/elements.dart';
-import '../js_backend/backend_helpers.dart' show BackendHelpers;
-import '../js_backend/js_backend.dart' show JavaScriptBackend;
-import '../types/types.dart' show TypeMask;
-import '../io/source_information.dart' show SourceInformation;
-
-/// Removes redundant `getInterceptor` calls.
-///
-/// The pass performs three optimizations for interceptors:
-///- pull interceptors out of loops
-///- replace interceptors with constants
-///- share interceptors when one is in scope of the other
-class ShareInterceptors extends TrampolineRecursiveVisitor implements Pass {
- String get passName => 'Share interceptors';
-
- /// The innermost loop containing a given primitive.
- final Map<Primitive, Continuation> loopHeaderFor =
- <Primitive, Continuation>{};
-
- /// An interceptor currently in scope for a given primitive.
- final Map<Primitive, Interceptor> interceptorFor = <Primitive, Interceptor>{};
-
- /// Interceptors that have been hoisted out of a given loop.
- final Map<Continuation, List<Interceptor>> loopHoistedInterceptors =
- <Continuation, List<Interceptor>>{};
-
- JavaScriptBackend backend;
- LoopHierarchy loopHierarchy;
- Continuation currentLoopHeader;
-
- ShareInterceptors(this.backend);
-
- BackendHelpers get helpers => backend.helpers;
-
- void rewrite(FunctionDefinition node) {
- loopHierarchy = new LoopHierarchy(node);
- visit(node.body);
- new ShareConstants().visit(node);
- }
-
- @override
- Expression traverseContinuation(Continuation cont) {
- Continuation oldLoopHeader = currentLoopHeader;
- currentLoopHeader = loopHierarchy.getLoopHeader(cont);
- for (Parameter param in cont.parameters) {
- loopHeaderFor[param] = currentLoopHeader;
- }
- if (cont.isRecursive) {
- pushAction(() {
- // After the loop body has been processed, all interceptors hoisted
- // to this loop fall out of scope and should be removed from the
- // environment.
- List<Interceptor> hoisted = loopHoistedInterceptors[cont];
- if (hoisted != null) {
- for (Interceptor interceptor in hoisted) {
- Primitive input = interceptor.input.definition;
- assert(interceptorFor[input] == interceptor);
- interceptorFor.remove(input);
- constifyInterceptor(interceptor);
- }
- }
- });
- }
- pushAction(() {
- currentLoopHeader = oldLoopHeader;
- });
- return cont.body;
- }
-
- /// If only one method table can be returned by the given interceptor,
- /// returns a constant for that method table.
- InterceptorConstantValue getInterceptorConstant(Interceptor node) {
- if (node.interceptedClasses.length == 1 &&
- node.isInterceptedClassAlwaysExact) {
- ClassElement interceptorClass = node.interceptedClasses.single;
- return new InterceptorConstantValue(interceptorClass.rawType);
- }
- return null;
- }
-
- bool hasNoFalsyValues(ClassElement class_) {
- return class_ != helpers.jsInterceptorClass &&
- class_ != helpers.jsNullClass &&
- class_ != helpers.jsBoolClass &&
- class_ != helpers.jsStringClass &&
- !class_.isSubclassOf(helpers.jsNumberClass);
- }
-
- Continuation getCurrentOuterLoop({Continuation scope}) {
- Continuation inner = null, outer = currentLoopHeader;
- while (outer != scope) {
- inner = outer;
- outer = loopHierarchy.getEnclosingLoop(outer);
- }
- return inner;
- }
-
- /// Binds the given constant in a primitive, in scope of the [useSite].
- ///
- /// The constant will be hoisted out of loops, and shared with other requests
- /// for the same constant as long as it is in scope.
- Primitive makeConstantFor(ConstantValue constant,
- {Expression useSite,
- TypeMask type,
- SourceInformation sourceInformation,
- Entity hint}) {
- Constant prim =
- new Constant(constant, sourceInformation: sourceInformation);
- prim.hint = hint;
- prim.type = type;
- LetPrim letPrim = new LetPrim(prim);
- Continuation loop = getCurrentOuterLoop();
- if (loop != null) {
- LetCont loopBinding = loop.parent;
- letPrim.insertAbove(loopBinding);
- } else {
- letPrim.insertAbove(useSite);
- }
- return prim;
- }
-
- void constifyInterceptor(Interceptor interceptor) {
- LetPrim let = interceptor.parent;
- InterceptorConstantValue constant = getInterceptorConstant(interceptor);
-
- if (constant == null) return;
-
- if (interceptor.isAlwaysIntercepted) {
- Primitive constantPrim = makeConstantFor(constant,
- useSite: let,
- type: interceptor.type,
- sourceInformation: interceptor.sourceInformation);
- constantPrim.useElementAsHint(interceptor.hint);
- constantPrim.substituteFor(interceptor);
- interceptor.destroy();
- let.remove();
- } else if (interceptor.isAlwaysNullOrIntercepted) {
- Primitive input = interceptor.input.definition;
- Primitive constantPrim = makeConstantFor(constant,
- useSite: let,
- type: interceptor.type.nonNullable(),
- sourceInformation: interceptor.sourceInformation);
- CpsFragment cps = new CpsFragment(interceptor.sourceInformation);
- Parameter param = new Parameter(interceptor.hint);
- Continuation cont = cps.letCont(<Parameter>[param]);
- if (interceptor.interceptedClasses.every(hasNoFalsyValues)) {
- // If null is the only falsy value, compile as "x && CONST".
- cps.ifFalsy(input).invokeContinuation(cont, [input]);
- } else {
- // If there are other falsy values compile as "x == null ? x : CONST".
- Primitive condition = cps.applyBuiltin(
- BuiltinOperator.LooseEq,
- [input, cps.makeNull()]);
- cps.ifTruthy(condition).invokeContinuation(cont, [input]);
- }
- cps.invokeContinuation(cont, [constantPrim]);
- cps.context = cont;
- cps.insertAbove(let);
- param.substituteFor(interceptor);
- interceptor.destroy();
- let.remove();
- }
- }
-
- @override
- Expression traverseLetPrim(LetPrim node) {
- loopHeaderFor[node.primitive] = currentLoopHeader;
- Expression next = node.body;
- if (node.primitive is! Interceptor) {
- return next;
- }
- Interceptor interceptor = node.primitive;
- Primitive input = interceptor.input.definition;
-
- // Try to reuse an existing interceptor for the same input.
- Interceptor existing = interceptorFor[input];
- if (existing != null) {
- existing.interceptedClasses.addAll(interceptor.interceptedClasses);
- existing.flags |= interceptor.flags;
- existing.substituteFor(interceptor);
- interceptor.destroy();
- node.remove();
- return next;
- }
-
- // Put this interceptor in the environment.
- interceptorFor[input] = interceptor;
-
- // Determine how far the interceptor can be lifted. The outermost loop
- // that contains the input binding should also contain the interceptor
- // binding.
- Continuation referencedLoop =
- lowestCommonAncestor(loopHeaderFor[input], currentLoopHeader);
- if (referencedLoop != currentLoopHeader) {
- Continuation hoistTarget = getCurrentOuterLoop(scope: referencedLoop);
- LetCont loopBinding = hoistTarget.parent;
- node.remove();
- node.insertAbove(loopBinding);
- // Remove the interceptor from the environment after processing the loop.
- loopHoistedInterceptors
- .putIfAbsent(hoistTarget, () => <Interceptor>[])
- .add(interceptor);
- } else {
- // Remove the interceptor from the environment when it falls out of scope.
- pushAction(() {
- assert(interceptorFor[input] == interceptor);
- interceptorFor.remove(input);
-
- // Now that the final set of intercepted classes has been seen, try to
- // replace it with a constant.
- constifyInterceptor(interceptor);
- });
- }
-
- return next;
- }
-
- /// Returns the the innermost loop that effectively encloses both
- /// c1 and c2 (or `null` if there is no such loop).
- Continuation lowestCommonAncestor(Continuation c1, Continuation c2) {
- int d1 = getDepth(c1), d2 = getDepth(c2);
- while (c1 != c2) {
- if (d1 <= d2) {
- c2 = loopHierarchy.getEnclosingLoop(c2);
- d2 = getDepth(c2);
- } else {
- c1 = loopHierarchy.getEnclosingLoop(c1);
- d1 = getDepth(c1);
- }
- }
- return c1;
- }
-
- int getDepth(Continuation loop) {
- if (loop == null) return -1;
- return loopHierarchy.loopDepth[loop];
- }
-}
-
-class ShareConstants extends TrampolineRecursiveVisitor {
- Map<ConstantValue, Constant> sharedConstantFor = <ConstantValue, Constant>{};
-
- Expression traverseLetPrim(LetPrim node) {
- Expression next = node.body;
- if (node.primitive is Constant && shouldShareConstant(node.primitive)) {
- Constant prim = node.primitive;
- Constant existing = sharedConstantFor[prim.value];
- if (existing != null) {
- existing.substituteFor(prim);
- existing.useElementAsHint(prim.hint);
- prim.destroy();
- node.remove();
- return next;
- }
- sharedConstantFor[prim.value] = prim;
- pushAction(() {
- assert(sharedConstantFor[prim.value] == prim);
- sharedConstantFor.remove(prim.value);
- });
- }
- return next;
- }
-
- bool shouldShareConstant(Constant constant) {
- return constant.value.isInterceptor;
- }
-}
diff --git a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
index a6017cb..422db14 100644
--- a/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
+++ b/pkg/compiler/lib/src/cps_ir/shrinking_reductions.dart
@@ -138,8 +138,7 @@
// Substitute the invocation argument for the continuation parameter.
for (int i = 0; i < invoke.arguments.length; i++) {
- Reference argRef = invoke.arguments[i];
- argRef.definition.substituteFor(cont.parameters[i]);
+ cont.parameters[i].replaceUsesWith(invoke.arguments[i].definition);
}
// Perform bookkeeping on substituted body and scan for new redexes.
@@ -168,7 +167,7 @@
Continuation wrappedCont = invoke.continuation.definition;
// Replace all occurrences with the wrapped continuation.
- wrappedCont.substituteFor(cont);
+ cont.replaceUsesWith(wrappedCont);
// Perform bookkeeping on removed body and scan for new redexes.
new _RemovalVisitor(_worklist).visit(cont);
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index a36f284..2329144 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -11,17 +11,14 @@
import '../elements/elements.dart';
import '../js_backend/backend_helpers.dart' show BackendHelpers;
import '../js_backend/js_backend.dart' show JavaScriptBackend;
+import '../types/abstract_value_domain.dart';
import '../types/types.dart';
import '../types/constants.dart' show computeTypeMask;
import '../universe/selector.dart' show Selector;
-import '../universe/call_structure.dart' show CallStructure;
import '../world.dart' show World;
+import '../closure.dart' show ClosureFieldElement, BoxLocal, TypeVariableLocal;
-enum AbstractBool {
- True, False, Maybe, Nothing
-}
-
-class TypeMaskSystem {
+class TypeMaskSystem implements AbstractValueDomain {
final TypesTask inferrer;
final World classWorld;
final JavaScriptBackend backend;
@@ -33,27 +30,69 @@
TypeMask __indexableTypeTest;
+ // The full type of a constant (e.g. a ContainerTypeMask) is not available on
+ // the constant. Type inference flows the type to some place where it is used,
+ // e.g. a parameter. For constant values that are the value of static const
+ // fields we need to remember the association.
+ final Map<ConstantValue, TypeMask> _constantMasks =
+ <ConstantValue, TypeMask>{};
+
+ @override
TypeMask get dynamicType => inferrer.dynamicType;
+
+ @override
TypeMask get typeType => inferrer.typeType;
+
+ @override
TypeMask get functionType => inferrer.functionType;
+
+ @override
TypeMask get boolType => inferrer.boolType;
+
+ @override
TypeMask get intType => inferrer.intType;
+
+ @override
TypeMask get doubleType => inferrer.doubleType;
+
+ @override
TypeMask get numType => inferrer.numType;
+
+ @override
TypeMask get stringType => inferrer.stringType;
+
+ @override
TypeMask get listType => inferrer.listType;
+
+ @override
TypeMask get mapType => inferrer.mapType;
+
+ @override
TypeMask get nonNullType => inferrer.nonNullType;
+
+ @override
TypeMask get nullType => inferrer.nullType;
+
+ @override
TypeMask get extendableArrayType => backend.extendableArrayType;
+
+ @override
TypeMask get fixedArrayType => backend.fixedArrayType;
+
+ @override
TypeMask get arrayType =>
new TypeMask.nonNullSubclass(helpers.jsArrayClass, classWorld);
+ @override
TypeMask get uint31Type => inferrer.uint31Type;
+
+ @override
TypeMask get uint32Type => inferrer.uint32Type;
+
+ @override
TypeMask get uintType => inferrer.positiveIntType;
+ @override
TypeMask get numStringBoolType {
if (_numStringBoolType == null) {
// Build the number+string+bool type. To make containment tests more
@@ -72,6 +111,7 @@
return _numStringBoolType;
}
+ @override
TypeMask get fixedLengthType {
if (_fixedLengthType == null) {
List<TypeMask> fixedLengthTypes =
@@ -84,6 +124,7 @@
return _fixedLengthType;
}
+ @override
TypeMask get interceptorType {
if (_interceptorType == null) {
_interceptorType =
@@ -92,6 +133,7 @@
return _interceptorType;
}
+ @override
TypeMask get interceptedTypes { // Does not include null.
if (_interceptedTypes == null) {
// We redundantly include subtypes of num/string/bool as intercepted
@@ -130,6 +172,7 @@
backend = compiler.backend {
}
+ @override
bool methodUsesReceiverArgument(FunctionElement function) {
assert(backend.isInterceptedMethod(function));
ClassElement clazz = function.enclosingClass.declaration;
@@ -137,18 +180,22 @@
classWorld.isUsedAsMixin(clazz);
}
+ @override
Element locateSingleElement(TypeMask mask, Selector selector) {
return mask.locateSingleElement(selector, mask, classWorld.compiler);
}
+ @override
ClassElement singleClass(TypeMask mask) {
return mask.singleClass(classWorld);
}
+ @override
bool needsNoSuchMethodHandling(TypeMask mask, Selector selector) {
return mask.needsNoSuchMethodHandling(selector, classWorld);
}
+ @override
TypeMask getReceiverType(MethodElement method) {
assert(method.isInstanceMember);
if (classWorld.isUsedAsMixin(method.enclosingClass.declaration)) {
@@ -161,14 +208,17 @@
}
}
+ @override
TypeMask getParameterType(ParameterElement parameter) {
return inferrer.getGuaranteedTypeOfElement(parameter);
}
+ @override
TypeMask getReturnType(FunctionElement function) {
return inferrer.getGuaranteedReturnTypeOfElement(function);
}
+ @override
TypeMask getInvokeReturnType(Selector selector, TypeMask mask) {
TypeMask result = inferrer.getGuaranteedTypeOfSelector(selector, mask);
// Tearing off .call from a function returns the function itself.
@@ -180,26 +230,53 @@
return result;
}
+ @override
TypeMask getFieldType(FieldElement field) {
+ if (field is ClosureFieldElement) {
+ // The type inference does not report types for all closure fields.
+ // Box fields are never null.
+ if (field.local is BoxLocal) return nonNullType;
+ // Closure fields for type variables contain the internal representation
+ // of the type (which can be null), not the Type object.
+ if (field.local is TypeVariableLocal) return dynamicType;
+ }
return inferrer.getGuaranteedTypeOfElement(field);
}
+ @override
TypeMask join(TypeMask a, TypeMask b) {
return a.union(b, classWorld);
}
+ @override
TypeMask intersection(TypeMask a, TypeMask b) {
if (a == null) return b;
if (b == null) return a;
return a.intersection(b, classWorld);
}
- TypeMask getTypeOf(ConstantValue constant) {
- return computeTypeMask(inferrer.compiler, constant);
+ void associateConstantValueWithElement(ConstantValue constant,
+ Element 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;
+ }
}
- // Returns the constant value if a TypeMask represents a single value.
- // Returns `null` if [mask] is not a constant.
+ @override
+ TypeMask getTypeOf(ConstantValue constant) {
+ return _constantMasks[constant] ??
+ computeTypeMask(inferrer.compiler, constant);
+ }
+
+ @override
ConstantValue getConstantOf(TypeMask mask) {
if (!mask.isValue) return null;
if (mask.isNullable) return null; // e.g. 'true or null'.
@@ -209,7 +286,9 @@
return null;
}
+ @override
TypeMask nonNullExact(ClassElement element) {
+ // TODO(johnniwinther): I don't think the follow is valid anymore.
// The class world does not know about classes created by
// closure conversion, so just treat those as a subtypes of Function.
// TODO(asgerf): Maybe closure conversion should create a new ClassWorld?
@@ -217,36 +296,43 @@
return new TypeMask.nonNullExact(element.declaration, classWorld);
}
+ @override
TypeMask nonNullSubclass(ClassElement element) {
if (element.isClosure) return functionType;
return new TypeMask.nonNullSubclass(element.declaration, classWorld);
}
+ @override
TypeMask nonNullSubtype(ClassElement element) {
if (element.isClosure) return functionType;
return new TypeMask.nonNullSubtype(element.declaration, classWorld);
}
+ @override
bool isDefinitelyBool(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().containsOnlyBool(classWorld);
}
+ @override
bool isDefinitelyNum(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().containsOnlyNum(classWorld);
}
+ @override
bool isDefinitelyString(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().containsOnlyString(classWorld);
}
+ @override
bool isDefinitelyNumStringBool(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return numStringBoolType.containsMask(t.nonNullable(), classWorld);
}
+ @override
bool isDefinitelyNotNumStringBool(TypeMask t) {
return areDisjoint(t, numStringBoolType);
}
@@ -255,6 +341,7 @@
///
/// This does not imply that the value is an integer, since most other values
/// such as null are also not a non-integer double.
+ @override
bool isDefinitelyNotNonIntegerDouble(TypeMask t) {
// Even though int is a subclass of double in the JS type system, we can
// still check this with disjointness, because [doubleType] is the *exact*
@@ -265,69 +352,82 @@
return areDisjoint(t, doubleType);
}
+ @override
bool isDefinitelyNonNegativeInt(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
// The JSPositiveInt class includes zero, despite the name.
return t.satisfies(helpers.jsPositiveIntClass, classWorld);
}
+ @override
bool isDefinitelyInt(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().containsOnlyInt(classWorld);
}
+ @override
bool isDefinitelyUint31(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.satisfies(helpers.jsUInt31Class, classWorld);
}
+ @override
bool isDefinitelyUint32(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.satisfies(helpers.jsUInt32Class, classWorld);
}
+ @override
bool isDefinitelyUint(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.satisfies(helpers.jsPositiveIntClass, classWorld);
}
+ @override
bool isDefinitelyArray(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().satisfies(helpers.jsArrayClass, classWorld);
}
+ @override
bool isDefinitelyMutableArray(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().satisfies(helpers.jsMutableArrayClass, classWorld);
}
+ @override
bool isDefinitelyFixedArray(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().satisfies(helpers.jsFixedArrayClass, classWorld);
}
+ @override
bool isDefinitelyExtendableArray(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().satisfies(helpers.jsExtendableArrayClass,
classWorld);
}
+ @override
bool isDefinitelyIndexable(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return _indexableTypeTest.containsMask(t.nonNullable(), classWorld);
}
+ @override
bool isDefinitelyMutableIndexable(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return t.nonNullable().satisfies(helpers.jsMutableIndexableClass,
classWorld);
}
+ @override
bool isDefinitelyFixedLengthIndexable(TypeMask t, {bool allowNull: false}) {
if (!allowNull && t.isNullable) return false;
return fixedLengthType.containsMask(t.nonNullable(), classWorld);
}
+ @override
bool isDefinitelyIntercepted(TypeMask t, {bool allowNull}) {
assert(allowNull != null);
if (!allowNull && t.isNullable) return false;
@@ -336,6 +436,7 @@
/// Given a class from the interceptor hierarchy, returns a [TypeMask]
/// matching all values with that interceptor (or a subtype thereof).
+ @override
TypeMask getInterceptorSubtypes(ClassElement class_) {
if (class_ == helpers.jsInterceptorClass) {
return interceptorType.nullable();
@@ -346,11 +447,18 @@
}
}
+ @override
bool areDisjoint(TypeMask leftType, TypeMask rightType) {
- TypeMask intersection = leftType.intersection(rightType, classWorld);
- return intersection.isEmpty && !intersection.isNullable;
+ TypeMask intersected = intersection(leftType, rightType);
+ return intersected.isEmpty && !intersected.isNullable;
}
+ @override
+ bool isMorePreciseOrEqual(TypeMask t1, TypeMask t2) {
+ return t2.containsMask(t1, classWorld);
+ }
+
+ @override
AbstractBool isSubtypeOf(TypeMask value,
types.DartType type,
{bool allowNull}) {
@@ -386,6 +494,7 @@
/// Returns whether [type] is one of the falsy values: false, 0, -0, NaN,
/// the empty string, or null.
+ @override
AbstractBool boolify(TypeMask type) {
if (isDefinitelyNotNumStringBool(type) && !type.isNullable) {
return AbstractBool.True;
@@ -393,12 +502,14 @@
return AbstractBool.Maybe;
}
+ @override
AbstractBool strictBoolify(TypeMask type) {
if (areDisjoint(type, boolType)) return AbstractBool.False;
return AbstractBool.Maybe;
}
/// Create a type mask containing at least all subtypes of [type].
+ @override
TypeMask subtypesOf(types.DartType type) {
if (type is types.InterfaceType) {
ClassElement element = type.element;
@@ -431,12 +542,14 @@
/// Returns a subset of [mask] containing at least the types
/// that can respond to [selector] without throwing.
+ @override
TypeMask receiverTypeFor(Selector selector, TypeMask mask) {
return classWorld.allFunctions.receiverType(selector, mask);
}
/// The result of an index operation on something of [type], or the dynamic
/// type if unknown.
+ @override
TypeMask elementTypeOfIndexable(TypeMask type) {
if (type is UnionTypeMask) {
return new TypeMask.unionOf(
@@ -458,6 +571,7 @@
}
/// The length of something of [type], or `null` if unknown.
+ @override
int getContainerLength(TypeMask type) {
if (type is ContainerTypeMask) {
return type.length;
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 9d1a335..8a4daba 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -30,42 +30,47 @@
import '../resolution/send_structure.dart';
import '../tree/tree.dart' as ast;
import '../types/types.dart';
+import '../types/abstract_value_domain.dart' show
+ AbstractBool;
import '../universe/selector.dart' show
Selector;
import '../world.dart' show World;
import 'cps_fragment.dart';
import 'cps_ir_nodes.dart';
import 'type_mask_system.dart';
+import '../closure.dart' show
+ ClosureFieldElement,
+ BoxLocal;
class ConstantPropagationLattice {
final TypeMaskSystem typeSystem;
final ConstantSystem constantSystem;
final types.DartTypes dartTypes;
- final AbstractValue anything;
- final AbstractValue nullValue;
+ final AbstractConstantValue anything;
+ final AbstractConstantValue nullValue;
ConstantPropagationLattice(TypeMaskSystem typeSystem,
this.constantSystem,
this.dartTypes)
: this.typeSystem = typeSystem,
- anything = new AbstractValue.nonConstant(typeSystem.dynamicType),
- nullValue = new AbstractValue.constantValue(
+ anything = new AbstractConstantValue.nonConstant(typeSystem.dynamicType),
+ nullValue = new AbstractConstantValue.constantValue(
new NullConstantValue(), new TypeMask.empty());
- final AbstractValue nothing = new AbstractValue.nothing();
+ final AbstractConstantValue nothing = new AbstractConstantValue.nothing();
- AbstractValue constant(ConstantValue value, [TypeMask type]) {
+ AbstractConstantValue constant(ConstantValue value, [TypeMask type]) {
if (type == null) type = typeSystem.getTypeOf(value);
- return new AbstractValue.constantValue(value, type);
+ return new AbstractConstantValue.constantValue(value, type);
}
- AbstractValue nonConstant([TypeMask type]) {
+ AbstractConstantValue nonConstant([TypeMask type]) {
if (type == null) type = typeSystem.dynamicType;
- return new AbstractValue.nonConstant(type);
+ return new AbstractConstantValue.nonConstant(type);
}
/// Compute the join of two values in the lattice.
- AbstractValue join(AbstractValue x, AbstractValue y) {
+ AbstractConstantValue join(AbstractConstantValue x, AbstractConstantValue y) {
assert(x != null);
assert(y != null);
@@ -76,36 +81,39 @@
} else if (x.isConstant && y.isConstant && x.constant == y.constant) {
return x;
} else {
- return new AbstractValue.nonConstant(typeSystem.join(x.type, y.type));
+ return new AbstractConstantValue.nonConstant(
+ typeSystem.join(x.type, y.type));
}
}
/// True if all members of this value are booleans.
- bool isDefinitelyBool(AbstractValue value, {bool allowNull: false}) {
+ bool isDefinitelyBool(AbstractConstantValue value, {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyBool(value.type, allowNull: allowNull);
}
/// True if all members of this value are numbers.
- bool isDefinitelyNum(AbstractValue value, {bool allowNull: false}) {
+ bool isDefinitelyNum(AbstractConstantValue value, {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyNum(value.type, allowNull: allowNull);
}
/// True if all members of this value are strings.
- bool isDefinitelyString(AbstractValue value, {bool allowNull: false}) {
+ bool isDefinitelyString(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyString(value.type, allowNull: allowNull);
}
/// True if all members of this value are numbers, strings, or booleans.
- bool isDefinitelyNumStringBool(AbstractValue value, {bool allowNull: false}) {
+ bool isDefinitelyNumStringBool(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyNumStringBool(value.type, allowNull: allowNull);
}
/// True if this value cannot be a string, number, or boolean.
- bool isDefinitelyNotNumStringBool(AbstractValue value) {
+ bool isDefinitelyNotNumStringBool(AbstractConstantValue value) {
return value.isNothing ||
typeSystem.isDefinitelyNotNumStringBool(value.type);
}
@@ -114,71 +122,72 @@
///
/// In other words, if true is returned, and the value is a number, then
/// it is a whole number and is not NaN, Infinity, or minus Infinity.
- bool isDefinitelyNotNonIntegerDouble(AbstractValue value) {
+ bool isDefinitelyNotNonIntegerDouble(AbstractConstantValue value) {
return value.isNothing ||
value.isConstant && !value.constant.isDouble ||
typeSystem.isDefinitelyNotNonIntegerDouble(value.type);
}
- bool isDefinitelyInt(AbstractValue value,
+ bool isDefinitelyInt(AbstractConstantValue value,
{bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyInt(value.type, allowNull: allowNull);
}
- bool isDefinitelyUint31(AbstractValue value,
- {bool allowNull: false}) {
+ bool isDefinitelyUint31(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyUint31(value.type, allowNull: allowNull);
}
- bool isDefinitelyUint32(AbstractValue value,
- {bool allowNull: false}) {
+ bool isDefinitelyUint32(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyUint32(value.type, allowNull: allowNull);
}
- bool isDefinitelyUint(AbstractValue value,
+ bool isDefinitelyUint(AbstractConstantValue value,
{bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyUint(value.type, allowNull: allowNull);
}
- bool isDefinitelyArray(AbstractValue value,
+ bool isDefinitelyArray(AbstractConstantValue value,
{bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyArray(value.type, allowNull: allowNull);
}
- bool isDefinitelyMutableArray(AbstractValue value,
+ bool isDefinitelyMutableArray(AbstractConstantValue value,
{bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyMutableArray(value.type,
allowNull: allowNull);
}
- bool isDefinitelyFixedArray(AbstractValue value,
- {bool allowNull: false}) {
+ bool isDefinitelyFixedArray(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyFixedArray(value.type,
+ allowNull: allowNull);
+ }
+
+ bool isDefinitelyExtendableArray(AbstractConstantValue value,
+ {bool allowNull: false}) {
+ return value.isNothing ||
+ typeSystem.isDefinitelyExtendableArray(value.type,
allowNull: allowNull);
}
- bool isDefinitelyExtendableArray(AbstractValue value,
- {bool allowNull: false}) {
- return value.isNothing ||
- typeSystem.isDefinitelyExtendableArray(value.type,
- allowNull: allowNull);
- }
-
- bool isDefinitelyIndexable(AbstractValue value, {bool allowNull: false}) {
+ bool isDefinitelyIndexable(AbstractConstantValue value,
+ {bool allowNull: false}) {
return value.isNothing ||
typeSystem.isDefinitelyIndexable(value.type, allowNull: allowNull);
}
/// Returns `true` if [value] represents an int value that must be in the
/// inclusive range.
- bool isDefinitelyIntInRange(AbstractValue value, {int min, int max}) {
+ bool isDefinitelyIntInRange(AbstractConstantValue value, {int min, int max}) {
if (value.isNothing) return true;
if (!isDefinitelyInt(value)) return false;
PrimitiveConstantValue constant = value.constant;
@@ -199,7 +208,7 @@
/// If [allowNull] is true, `null` is considered an instance of anything,
/// otherwise it is only considered an instance of [Object], [dynamic], and
/// [Null].
- AbstractBool isSubtypeOf(AbstractValue value,
+ AbstractBool isSubtypeOf(AbstractConstantValue value,
types.DartType type,
{bool allowNull}) {
assert(allowNull != null);
@@ -245,7 +254,8 @@
///
/// This method returns `null` if a good result could not be found. In that
/// case, it is best to fall back on interprocedural type information.
- AbstractValue unaryOp(UnaryOperator operator, AbstractValue value) {
+ AbstractConstantValue unaryOp(UnaryOperator operator,
+ AbstractConstantValue value) {
switch (operator.kind) {
case UnaryOperatorKind.COMPLEMENT:
return bitNotSpecial(value);
@@ -276,9 +286,9 @@
///
/// This method returns `null` if a good result could not be found. In that
/// case, it is best to fall back on interprocedural type information.
- AbstractValue binaryOp(BinaryOperator operator,
- AbstractValue left,
- AbstractValue right) {
+ AbstractConstantValue binaryOp(BinaryOperator operator,
+ AbstractConstantValue left,
+ AbstractConstantValue right) {
switch (operator.kind) {
case BinaryOperatorKind.ADD:
return addSpecial(left, right);
@@ -343,7 +353,8 @@
return null; // The caller will use return type from type inference.
}
- AbstractValue foldUnary(UnaryOperation operation, AbstractValue value) {
+ AbstractConstantValue foldUnary(UnaryOperation operation,
+ AbstractConstantValue value) {
if (value.isNothing) return nothing;
if (value.isConstant) {
ConstantValue result = operation.fold(value.constant);
@@ -352,20 +363,20 @@
return null;
}
- AbstractValue bitNotSpecial(AbstractValue value) {
+ AbstractConstantValue bitNotSpecial(AbstractConstantValue value) {
return foldUnary(constantSystem.bitNot, value);
}
- AbstractValue negateSpecial(AbstractValue value) {
- AbstractValue folded = foldUnary(constantSystem.negate, value);
+ AbstractConstantValue negateSpecial(AbstractConstantValue value) {
+ AbstractConstantValue folded = foldUnary(constantSystem.negate, value);
if (folded != null) return folded;
if (isDefinitelyInt(value)) return nonConstant(typeSystem.intType);
return null;
}
- AbstractValue foldBinary(BinaryOperation operation,
- AbstractValue left, AbstractValue right) {
+ AbstractConstantValue foldBinary(BinaryOperation operation,
+ AbstractConstantValue left, AbstractConstantValue right) {
if (left.isNothing || right.isNothing) return nothing;
if (left.isConstant && right.isConstant) {
ConstantValue result = operation.fold(left.constant, right.constant);
@@ -374,32 +385,37 @@
return null;
}
- AbstractValue closedOnInt(AbstractValue left, AbstractValue right) {
- if (isDefinitelyInt(left) && isDefinitelyInt(right)) {
+ AbstractConstantValue closedOnInt(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ if (isDefinitelyInt(left) && isDefinitelyInt(right, allowNull: true)) {
return nonConstant(typeSystem.intType);
}
return null;
}
- AbstractValue closedOnUint(AbstractValue left, AbstractValue right) {
- if (isDefinitelyUint(left) && isDefinitelyUint(right)) {
+ AbstractConstantValue closedOnUint(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ if (isDefinitelyUint(left) && isDefinitelyUint(right, allowNull: true)) {
return nonConstant(typeSystem.uintType);
}
return null;
}
- AbstractValue closedOnUint31(AbstractValue left, AbstractValue right) {
- if (isDefinitelyUint31(left) && isDefinitelyUint31(right)) {
+ AbstractConstantValue closedOnUint31(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ if (isDefinitelyUint31(left) && isDefinitelyUint31(right, allowNull: true)) {
return nonConstant(typeSystem.uint31Type);
}
return null;
}
- AbstractValue addSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.add, left, right);
+ AbstractConstantValue addSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ 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);
@@ -407,30 +423,35 @@
return null;
}
- AbstractValue subtractSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.subtract, left, right);
+ AbstractConstantValue subtractSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.subtract, left, right);
return folded ?? closedOnInt(left, right);
}
- AbstractValue multiplySpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.multiply, left, right);
+ AbstractConstantValue multiplySpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.multiply, left, right);
return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
}
- AbstractValue divideSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue divideSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.divide, left, right);
}
- AbstractValue truncatingDivideSpecial(
- AbstractValue left, AbstractValue right) {
- AbstractValue folded =
+ AbstractConstantValue truncatingDivideSpecial(
+ AbstractConstantValue left, AbstractConstantValue right) {
+ AbstractConstantValue folded =
foldBinary(constantSystem.truncatingDivide, left, right);
if (folded != null) return folded;
if (isDefinitelyNum(left)) {
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);
@@ -441,19 +462,29 @@
return null;
}
- AbstractValue moduloSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.modulo, left, right);
+ AbstractConstantValue moduloSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.modulo, left, right);
return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
}
- AbstractValue remainderSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue remainderSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
if (left.isNothing || right.isNothing) return nothing;
- AbstractValue folded = null; // Remainder not in constant system.
+ AbstractConstantValue folded = null; // Remainder not in constant system.
return folded ?? closedOnUint(left, right) ?? closedOnInt(left, right);
}
- AbstractValue equalSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.equal, left, right);
+ AbstractConstantValue codeUnitAtSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ return foldBinary(constantSystem.codeUnitAt, left, right);
+ }
+
+ AbstractConstantValue equalSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.equal, left, right);
if (folded != null) return folded;
bool behavesLikeIdentity =
isDefinitelyNumStringBool(left, allowNull: true) ||
@@ -465,11 +496,14 @@
return null;
}
- AbstractValue andSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.bitAnd, left, right);
+ AbstractConstantValue andSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ 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);
}
@@ -477,22 +511,29 @@
return null;
}
- AbstractValue orSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.bitOr, left, right);
+ AbstractConstantValue orSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.bitOr, left, right);
return folded ?? closedOnUint31(left, right);
}
- AbstractValue xorSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.bitXor, left, right);
+ AbstractConstantValue xorSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.bitXor, left, right);
return folded ?? closedOnUint31(left, right);
}
- AbstractValue shiftLeftSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue shiftLeftSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.shiftLeft, left, right);
}
- AbstractValue shiftRightSpecial(AbstractValue left, AbstractValue right) {
- AbstractValue folded = foldBinary(constantSystem.shiftRight, left, right);
+ AbstractConstantValue shiftRightSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
+ AbstractConstantValue folded =
+ foldBinary(constantSystem.shiftRight, left, right);
if (folded != null) return folded;
if (isDefinitelyUint31(left)) {
return nonConstant(typeSystem.uint31Type);
@@ -506,27 +547,51 @@
return null;
}
- AbstractValue lessSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue lessSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.less, left, right);
}
- AbstractValue lessEqualSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue lessEqualSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.lessEqual, left, right);
}
- AbstractValue greaterSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue greaterSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.greater, left, right);
}
- AbstractValue greaterEqualSpecial(AbstractValue left, AbstractValue right) {
+ AbstractConstantValue greaterEqualSpecial(AbstractConstantValue left,
+ AbstractConstantValue right) {
return foldBinary(constantSystem.greaterEqual, left, right);
}
- AbstractValue stringConstant(String value) {
+ AbstractConstantValue intConstant(int value) {
+ return constant(new IntConstantValue(value));
+ }
+
+ AbstractConstantValue lengthSpecial(AbstractConstantValue input) {
+ if (input.isConstant) {
+ ConstantValue constant = input.constant;
+ if (constant is StringConstantValue) {
+ return intConstant(constant.length);
+ } else if (constant is ListConstantValue) {
+ return intConstant(constant.length);
+ }
+ }
+ int length = typeSystem.getContainerLength(input.type);
+ if (length != null) {
+ return intConstant(length);
+ }
+ return null; // The caller will use return type from type inference.
+ }
+
+ AbstractConstantValue stringConstant(String value) {
return constant(new StringConstantValue(new ast.DartString.literal(value)));
}
- AbstractValue stringify(AbstractValue value) {
+ AbstractConstantValue stringify(AbstractConstantValue value) {
if (value.isNothing) return nothing;
if (value.isNonConst) return nonConstant(typeSystem.stringType);
ConstantValue constantValue = value.constant;
@@ -544,7 +609,7 @@
/// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
/// the empty string, or null.
- AbstractBool boolify(AbstractValue value) {
+ AbstractBool boolify(AbstractConstantValue value) {
if (value.isNothing) return AbstractBool.Nothing;
if (value.isConstant) {
ConstantValue constantValue = value.constant;
@@ -558,7 +623,7 @@
}
/// Returns whether [value] is the value `true`.
- AbstractBool strictBoolify(AbstractValue value) {
+ AbstractBool strictBoolify(AbstractConstantValue value) {
if (value.isNothing) return AbstractBool.Nothing;
if (value.isConstant) {
return value.constant.isTrue ? AbstractBool.True : AbstractBool.False;
@@ -569,11 +634,11 @@
/// The possible return types of a method that may be targeted by
/// [typedSelector]. If the given selector is not a [TypedSelector], any
/// reachable method matching the selector may be targeted.
- AbstractValue getInvokeReturnType(Selector selector, TypeMask mask) {
+ AbstractConstantValue getInvokeReturnType(Selector selector, TypeMask mask) {
return fromMask(typeSystem.getInvokeReturnType(selector, mask));
}
- AbstractValue fromMask(TypeMask mask) {
+ AbstractConstantValue fromMask(TypeMask mask) {
ConstantValue constantValue = typeSystem.getConstantOf(mask);
if (constantValue != null) return constant(constantValue, mask);
return nonConstant(mask);
@@ -613,14 +678,11 @@
@override
void rewrite(FunctionDefinition root) {
- Map<Expression, ConstantValue> replacements = <Expression, ConstantValue>{};
-
// Analyze. In this phase, the entire term is analyzed for reachability
// and the abstract value of each expression.
TypePropagationVisitor analyzer = new TypePropagationVisitor(
_lattice,
_values,
- replacements,
_internalError);
analyzer.analyze(root);
@@ -633,7 +695,6 @@
_functionCompiler,
_lattice,
analyzer,
- replacements,
_internalError);
transformer.transform(root);
}
@@ -660,7 +721,6 @@
*/
class TransformingVisitor extends DeepRecursiveVisitor {
final TypePropagationVisitor analyzer;
- final Map<Expression, ConstantValue> replacements;
final ConstantPropagationLattice lattice;
final dart2js.Compiler compiler;
final CpsFunctionCompiler functionCompiler;
@@ -680,10 +740,24 @@
this.functionCompiler,
this.lattice,
this.analyzer,
- this.replacements,
this.internalError);
void transform(FunctionDefinition root) {
+ // If one of the parameters has no value, the function is unreachable.
+ // We assume all values in scope have a non-empty type (otherwise the
+ // scope is unreachable), so this optimization is required.
+ // TODO(asgerf): Can we avoid emitting the function is the first place?
+ for (Parameter param in root.parameters) {
+ if (getValue(param).isNothing) {
+ // Replace with `throw "Unreachable";`
+ CpsFragment cps = new CpsFragment(null);
+ Primitive message = cps.makeConstant(
+ new StringConstantValue.fromString("Unreachable"));
+ cps.put(new Throw(message));
+ replaceSubtree(root.body, cps.result);
+ return;
+ }
+ }
push(root.body);
while (stack.isNotEmpty) {
visit(stack.removeLast());
@@ -719,39 +793,66 @@
}
void visitLetPrim(LetPrim node) {
- AbstractValue value = getValue(node.primitive);
- if (node.primitive is! Constant &&
- node.primitive is! Refinement &&
- node.primitive.isSafeForElimination &&
- value.isConstant) {
- // If the value is a known constant, compile it as a constant.
- Constant newPrim = makeConstantPrimitive(value.constant);
- newPrim.substituteFor(node.primitive);
- RemovalVisitor.remove(node.primitive);
- node.primitive = newPrim;
- newPrim.parent = node;
- } else {
- Primitive newPrim = visit(node.primitive);
- if (newPrim != null) {
- newPrim.substituteFor(node.primitive);
- RemovalVisitor.remove(node.primitive);
- node.primitive = newPrim;
- newPrim.parent = node;
- reanalyze(newPrim);
- }
- if (node.primitive.hasNoUses && node.primitive.isSafeForElimination) {
- // Remove unused primitives before entering the body.
- // This would also be done by shrinking reductions, but usage analyses
- // such as isAlwaysBoolified are more precise without the dead uses, so
- // we prefer to remove them early.
- RemovalVisitor.remove(node.primitive);
- node.parent.body = node.body;
- node.body.parent = node.parent;
+ Primitive prim = node.primitive;
+
+ // Try to remove a dead primitive.
+ if (prim.hasNoUses && prim.isSafeForElimination) {
+ push(node.body);
+ prim.destroy();
+ node.remove();
+ return;
+ }
+
+ // Try to constant-fold the primitive.
+ if (prim is! Constant && prim is! Refinement && prim.isSafeForElimination) {
+ AbstractConstantValue value = getValue(prim);
+ if (value.isConstant) {
+ prim.replaceWith(makeConstantPrimitive(value.constant));
+ push(node.body);
+ return;
}
}
+
+ // Try to specialize the primitive.
+ var replacement = visit(prim);
+ if (replacement is CpsFragment) {
+ reanalyzeFragment(replacement);
+ replacement.insertBelow(node);
+ push(node.body); // Get the body before removing the node.
+ prim.destroy();
+ node.remove();
+ return;
+ }
+ if (replacement is Primitive) {
+ prim.replaceWith(replacement);
+ reanalyze(replacement);
+ // Reanalyze this node. Further specialization may be possible.
+ push(node);
+ return;
+ }
+ assert(replacement == null);
+
+ // Remove dead code after a primitive that always throws.
+ if (isAlwaysThrowingOrDiverging(prim)) {
+ replaceSubtree(node.body, new Unreachable());
+ return;
+ }
+
push(node.body);
}
+ bool isAlwaysThrowingOrDiverging(Primitive prim) {
+ if (prim is SetField) {
+ return getValue(prim.object.definition).isNullConstant;
+ }
+ if (prim is SetIndex) {
+ return getValue(prim.object.definition).isNullConstant;
+ }
+ // If a primitive has a value, but can't return anything, it must throw
+ // or diverge.
+ return prim.hasValue && prim.type.isEmpty && !prim.type.isNullable;
+ }
+
void visitContinuation(Continuation node) {
if (node.isReturnContinuation) return;
if (!analyzer.reachableContinuations.contains(node)) {
@@ -771,27 +872,35 @@
analyzer.reanalyzeSubtree(node);
}
+ /// Sets parent pointers and computes types for the given fragment.
+ void reanalyzeFragment(CpsFragment code) {
+ if (code.isEmpty) return;
+ if (code.isOpen) {
+ // Temporarily close the fragment while analyzing it.
+ // TODO(asgerf): Perhaps the analyzer should just cope with missing nodes.
+ InteriorNode context = code.context;
+ code.put(new Unreachable());
+ reanalyze(code.root);
+ code.context = context;
+ context.body = null;
+ } else {
+ reanalyze(code.root);
+ }
+ }
+
/// Removes the entire subtree of [node] and inserts [replacement].
///
- /// By default, all references in the [node] subtree are unlinked, and parent
- /// pointers in [replacement] are initialized and its types recomputed.
- ///
- /// If the caller needs to manually unlink the node, because some references
- /// were adopted by other nodes, it can be disabled by passing `false`
- /// as the [unlink] parameter.
+ /// All references in the [node] subtree are unlinked all types in
+ /// [replacement] are recomputed.
///
/// [replacement] must be "fresh", i.e. it must not contain significant parts
- /// of the original IR inside of it since the [ParentVisitor] will
- /// redundantly reprocess it.
- void replaceSubtree(Expression node, Expression replacement,
- {bool unlink: true}) {
+ /// of the original IR inside of it, as this leads to redundant reprocessing.
+ void replaceSubtree(Expression node, Expression replacement) {
InteriorNode parent = node.parent;
parent.body = replacement;
replacement.parent = parent;
node.parent = null;
- if (unlink) {
- RemovalVisitor.remove(node);
- }
+ RemovalVisitor.remove(node);
reanalyze(replacement);
}
@@ -818,16 +927,6 @@
node.parent = context;
}
- /// Binds [prim] before [node].
- void insertLetPrim(Expression node, Primitive prim) {
- InteriorNode parent = node.parent;
- LetPrim let = new LetPrim(prim);
- parent.body = let;
- let.body = node;
- node.parent = let;
- let.parent = parent;
- }
-
/// Make a constant primitive for [constant] and set its entry in [values].
Constant makeConstantPrimitive(ConstantValue constant) {
Constant primitive = new Constant(constant);
@@ -864,7 +963,7 @@
Continuation trueCont = node.trueContinuation.definition;
Continuation falseCont = node.falseContinuation.definition;
Primitive condition = node.condition.definition;
- AbstractValue conditionValue = getValue(condition);
+ AbstractConstantValue conditionValue = getValue(condition);
// Change to non-strict check if the condition is a boolean or null.
if (lattice.isDefinitelyBool(conditionValue, allowNull: true)) {
@@ -889,44 +988,6 @@
push(invoke);
return;
}
-
- if (condition is ApplyBuiltinOperator &&
- (condition.operator == BuiltinOperator.LooseEq ||
- condition.operator == BuiltinOperator.StrictEq)) {
- Primitive leftArg = condition.arguments[0].definition;
- Primitive rightArg = condition.arguments[1].definition;
- AbstractValue left = getValue(leftArg);
- AbstractValue right = getValue(rightArg);
- if (right.isNullConstant &&
- lattice.isDefinitelyNotNumStringBool(left)) {
- // Rewrite:
- // if (x == null) S1 else S2
- // =>
- // if (x) S2 else S1 (note the swapped branches)
- Branch branch = new Branch.loose(leftArg, falseCont, trueCont);
- replaceSubtree(node, branch);
- return;
- } else if (left.isNullConstant &&
- lattice.isDefinitelyNotNumStringBool(right)) {
- Branch branch = new Branch.loose(rightArg, falseCont, trueCont);
- replaceSubtree(node, branch);
- return;
- } else if (right.isTrueConstant &&
- lattice.isDefinitelyBool(left, allowNull: true)) {
- // Rewrite:
- // if (x == true) S1 else S2
- // =>
- // if (x) S1 else S2
- Branch branch = new Branch.loose(leftArg, trueCont, falseCont);
- replaceSubtree(node, branch);
- return;
- } else if (left.isTrueConstant &&
- lattice.isDefinitelyBool(right, allowNull: true)) {
- Branch branch = new Branch.loose(rightArg, trueCont, falseCont);
- replaceSubtree(node, branch);
- return;
- }
- }
}
void visitInvokeContinuation(InvokeContinuation node) {
@@ -941,8 +1002,10 @@
!cont.isRecursive &&
!node.isEscapingTry) {
for (int i = 0; i < node.arguments.length; ++i) {
- node.arguments[i].definition.useElementAsHint(cont.parameters[i].hint);
- node.arguments[i].definition.substituteFor(cont.parameters[i]);
+ Primitive argument = node.arguments[i].definition;
+ Parameter parameter = cont.parameters[i];
+ argument.useElementAsHint(parameter.hint);
+ parameter.replaceUsesWith(argument);
node.arguments[i].unlink();
}
node.continuation.unlink();
@@ -967,34 +1030,70 @@
/// Replaces [node] with a more specialized instruction, if possible.
///
/// Returns `true` if the node was replaced.
- bool specializeOperatorCall(InvokeMethod node) {
- Continuation cont = node.continuation.definition;
- bool replaceWithPrimitive(Primitive prim) {
- LetPrim let = makeLetPrimInvoke(prim, cont);
- replaceSubtree(node, let);
- push(let);
- return true; // So returning early is more convenient.
- }
- bool replaceWithBinary(BuiltinOperator operator,
- Primitive left,
- Primitive right) {
- return replaceWithPrimitive(
- new ApplyBuiltinOperator(
- operator, <Primitive>[left, right], node.sourceInformation));
- }
- bool replaceWithUnary(BuiltinOperator operator, Primitive argument) {
- return replaceWithPrimitive(
- new ApplyBuiltinOperator(
- operator, <Primitive>[argument], node.sourceInformation));
- }
-
+ specializeOperatorCall(InvokeMethod node) {
bool trustPrimitives = compiler.trustPrimitives;
+ /// Checks that the the receiver satisfied the given predicate [guard],
+ /// otherwise ensures a [NoSuchMethodError] will be thrown.
+ ///
+ /// For example, if the [guard] is `IsNumber` for a call to `<`:
+ ///
+ /// if (typeof x !== 'number') return x.$lt();
+ ///
+ /// The [guard] must accept all possible non-null values for the receiver,
+ /// but should be as specific as possible so the VM gets more information
+ /// from the check.
+ Primitive guardReceiver(CpsFragment cps, BuiltinOperator guard) {
+ if (guard == null || getValue(node.dartReceiver).isDefinitelyNotNull) {
+ return node.dartReceiver;
+ }
+ if (!trustPrimitives) {
+ Primitive check = cps.applyBuiltin(guard, [node.dartReceiver]);
+ cps.ifFalsy(check)
+ ..invokeMethod(node.dartReceiver, node.selector,
+ typeSystem.nullType, [])
+ ..put(new Unreachable());
+ }
+ // Refine the receiver to be non-null for use in the operator.
+ // This restricts code motion and improves the type computed for the
+ // built-in operator that depends on it.
+ // This must be done even if trusting primitives.
+ Primitive refined = cps.letPrim(
+ new Refinement(node.dartReceiver, typeSystem.nonNullType));
+ return refined;
+ }
+
+ /// Replaces the call with [operator], using the receiver and first argument
+ /// as operands (in that order).
+ ///
+ /// If [guard] is given, the receiver is checked using [guardReceiver],
+ /// unless it is known kot to be null.
+ CpsFragment makeBinary(BuiltinOperator operator, {BuiltinOperator guard}) {
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive left = guardReceiver(cps, guard);
+ Primitive right = node.dartArgument(0);
+ Primitive result = cps.applyBuiltin(operator, [left, right]);
+ result.hint = node.hint;
+ node.replaceUsesWith(result);
+ return cps;
+ }
+
+ /// Like [makeBinary] but for unary operators with the receiver as the
+ /// argument.
+ CpsFragment makeUnary(BuiltinOperator operator, {BuiltinOperator guard}) {
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive argument = guardReceiver(cps, guard);
+ Primitive result = cps.applyBuiltin(operator, [argument]);
+ result.hint = node.hint;
+ node.replaceUsesWith(result);
+ return cps;
+ }
+
if (node.selector.isOperator && node.arguments.length == 2) {
- Primitive leftArg = getDartReceiver(node);
- Primitive rightArg = getDartArgument(node, 0);
- AbstractValue left = getValue(leftArg);
- AbstractValue right = getValue(rightArg);
+ Primitive leftArg = node.dartReceiver;
+ Primitive rightArg = node.dartArgument(0);
+ AbstractConstantValue left = getValue(leftArg);
+ AbstractConstantValue right = getValue(rightArg);
String opname = node.selector.name;
if (opname == '==') {
@@ -1002,8 +1101,7 @@
// fact that Dart-null corresponds to both JS-null and JS-undefined.
// Please see documentation for IsFalsy, StrictEq, and LooseEq.
if (left.isNullConstant || right.isNullConstant) {
- return replaceWithBinary(BuiltinOperator.Identical,
- leftArg, rightArg);
+ return makeBinary(BuiltinOperator.Identical);
}
// There are several implementations of == that behave like identical.
// Specialize it if we definitely call one of those.
@@ -1018,98 +1116,113 @@
}
}
if (behavesLikeIdentical) {
- return replaceWithBinary(BuiltinOperator.Identical,
- leftArg, rightArg);
+ return makeBinary(BuiltinOperator.Identical);
}
} else {
- if (lattice.isDefinitelyNum(left, allowNull: trustPrimitives) &&
+ if (lattice.isDefinitelyNum(left, allowNull: true) &&
lattice.isDefinitelyNum(right, allowNull: trustPrimitives)) {
// Try to insert a numeric operator.
BuiltinOperator operator = NumBinaryBuiltins[opname];
if (operator != null) {
- return replaceWithBinary(operator, leftArg, rightArg);
+ return makeBinary(operator, guard: BuiltinOperator.IsNumber);
}
// Shift operators are not in [NumBinaryBuiltins] because Dart shifts
// behave different to JS shifts, especially in the handling of the
// shift count.
// Try to insert a shift-left operator.
if (opname == '<<' &&
- lattice.isDefinitelyInt(left, allowNull: trustPrimitives) &&
+ lattice.isDefinitelyInt(left, allowNull: true) &&
lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
- return replaceWithBinary(BuiltinOperator.NumShl, leftArg, rightArg);
+ return makeBinary(BuiltinOperator.NumShl,
+ guard: BuiltinOperator.IsNumber);
}
// Try to insert a shift-right operator. JavaScript's right shift is
// consistent with Dart's only for left operands in the unsigned
// 32-bit range.
if (opname == '>>' &&
- lattice.isDefinitelyUint32(left, allowNull: trustPrimitives) &&
+ lattice.isDefinitelyUint32(left, allowNull: true) &&
lattice.isDefinitelyIntInRange(right, min: 0, max: 31)) {
- return replaceWithBinary(BuiltinOperator.NumShr, leftArg, rightArg);
+ return makeBinary(BuiltinOperator.NumShr,
+ guard: BuiltinOperator.IsNumber);
}
// Try to use remainder for '%'. Both operands must be non-negative
// and the divisor must be non-zero.
if (opname == '%' &&
- lattice.isDefinitelyUint(left, allowNull: trustPrimitives) &&
+ lattice.isDefinitelyUint(left, allowNull: true) &&
lattice.isDefinitelyUint(right) &&
lattice.isDefinitelyIntInRange(right, min: 1)) {
- return replaceWithBinary(
- BuiltinOperator.NumRemainder, leftArg, rightArg);
+ return makeBinary(BuiltinOperator.NumRemainder,
+ guard: BuiltinOperator.IsNumber);
}
if (opname == '~/' &&
- lattice.isDefinitelyUint32(left, allowNull: trustPrimitives) &&
+ lattice.isDefinitelyUint32(left, allowNull: true) &&
lattice.isDefinitelyIntInRange(right, min: 2)) {
- return replaceWithBinary(
- BuiltinOperator.NumTruncatingDivideToSigned32,
- leftArg, rightArg);
+ return makeBinary(BuiltinOperator.NumTruncatingDivideToSigned32,
+ guard: BuiltinOperator.IsNumber);
}
}
if (lattice.isDefinitelyString(left, allowNull: trustPrimitives) &&
lattice.isDefinitelyString(right, allowNull: trustPrimitives) &&
opname == '+') {
- return replaceWithBinary(BuiltinOperator.StringConcatenate,
- leftArg, rightArg);
+ // TODO(asgerf): Add IsString builtin so we can use a guard here.
+ return makeBinary(BuiltinOperator.StringConcatenate);
}
}
}
if (node.selector.isOperator && node.arguments.length == 1) {
- Primitive argument = getDartReceiver(node);
- AbstractValue value = getValue(argument);
+ Primitive argument = node.dartReceiver;
+ AbstractConstantValue value = getValue(argument);
- if (lattice.isDefinitelyNum(value, allowNull: false)) {
+ if (lattice.isDefinitelyNum(value, allowNull: true)) {
String opname = node.selector.name;
if (opname == '~') {
- return replaceWithUnary(BuiltinOperator.NumBitNot, argument);
+ return makeUnary(BuiltinOperator.NumBitNot,
+ guard: BuiltinOperator.IsNumber);
}
if (opname == 'unary-') {
- return replaceWithUnary(BuiltinOperator.NumNegate, argument);
+ return makeUnary(BuiltinOperator.NumNegate,
+ guard: BuiltinOperator.IsNumber);
}
}
}
if (node.selector.isCall) {
String name = node.selector.name;
- Primitive receiver = getDartReceiver(node);
- AbstractValue receiverValue = getValue(receiver);
+ Primitive receiver = node.dartReceiver;
+ AbstractConstantValue receiverValue = getValue(receiver);
if (name == 'remainder') {
if (node.arguments.length == 2) {
- Primitive arg = getDartArgument(node, 0);
- AbstractValue argValue = getValue(arg);
- if (lattice.isDefinitelyInt(receiverValue) &&
+ Primitive arg = node.dartArgument(0);
+ AbstractConstantValue argValue = getValue(arg);
+ if (lattice.isDefinitelyInt(receiverValue, allowNull: true) &&
lattice.isDefinitelyInt(argValue) &&
isIntNotZero(argValue)) {
- return
- replaceWithBinary(BuiltinOperator.NumRemainder, receiver, arg);
+ return makeBinary(BuiltinOperator.NumRemainder,
+ guard: BuiltinOperator.IsNumber);
+ }
+ }
+ } else if (name == 'codeUnitAt') {
+ if (node.arguments.length == 2) {
+ Primitive index = node.dartArgument(0);
+ if (lattice.isDefinitelyString(receiverValue) &&
+ lattice.isDefinitelyInt(getValue(index))) {
+ SourceInformation sourceInfo = node.sourceInformation;
+ CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
+ ApplyBuiltinOperator get =
+ cps.applyBuiltin(BuiltinOperator.CharCodeAt,
+ <Primitive>[receiver, index]);
+ node.replaceUsesWith(get);
+ get.hint = node.hint;
+ return cps;
}
}
}
}
- // We should only get here if the node was not specialized.
- assert(node.parent != null);
- return false;
+ return null;
}
/// Returns `true` if [value] represents an int value that cannot be zero.
- bool isIntNotZero(AbstractValue value) {
+ bool isIntNotZero(AbstractConstantValue value) {
return lattice.isDefinitelyIntInRange(value, min: 1) ||
lattice.isDefinitelyIntInRange(value, max: -1);
}
@@ -1118,56 +1231,29 @@
return backend.isInterceptedSelector(selector);
}
- Primitive getDartReceiver(InvokeMethod node) {
- if (node.receiverIsIntercepted) {
- return node.arguments[0].definition;
- } else {
- return node.receiver.definition;
- }
- }
-
- Primitive getDartArgument(InvokeMethod node, int n) {
- if (isInterceptedSelector(node.selector)) {
- return node.arguments[n+1].definition;
- } else {
- return node.arguments[n].definition;
- }
- }
-
/// If [node] is a getter or setter invocation, tries to replace the
/// invocation with a direct access to a field.
///
/// Returns `true` if the node was replaced.
- bool specializeFieldAccess(InvokeMethod node) {
- if (!node.selector.isGetter && !node.selector.isSetter) return false;
- AbstractValue receiver = getValue(getDartReceiver(node));
+ Primitive specializeFieldAccess(InvokeMethod node) {
+ if (!node.selector.isGetter && !node.selector.isSetter) return null;
+ AbstractConstantValue receiver = getValue(node.dartReceiver);
Element target =
typeSystem.locateSingleElement(receiver.type, node.selector);
- if (target is! FieldElement) return false;
+ if (target is! FieldElement) return null;
// TODO(asgerf): Inlining native fields will make some tests pass for the
// wrong reason, so for testing reasons avoid inlining them.
if (backend.isNative(target) || backend.isJsInterop(target)) {
- return false;
+ return null;
}
- Continuation cont = node.continuation.definition;
if (node.selector.isGetter) {
- GetField get = new GetField(getDartReceiver(node), target);
- LetPrim let = makeLetPrimInvoke(get, cont);
- replaceSubtree(node, let);
- push(let);
- return true;
+ return new GetField(node.dartReceiver, target);
} else {
- if (target.isFinal) return false;
- assert(cont.parameters.single.hasNoUses);
- cont.parameters.clear();
- CpsFragment cps = new CpsFragment(node.sourceInformation);
- cps.letPrim(new SetField(getDartReceiver(node),
- target,
- getDartArgument(node, 0)));
- cps.invokeContinuation(cont);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ if (target.isFinal) return null;
+ assert(node.hasNoUses);
+ return new SetField(node.dartReceiver,
+ target,
+ node.dartArgument(0));
}
}
@@ -1185,10 +1271,12 @@
return cps;
}
Continuation fail = cps.letCont();
- Primitive isTooSmall = cps.applyBuiltin(
- BuiltinOperator.NumLt,
- <Primitive>[index, cps.makeZero()]);
- cps.ifTruthy(isTooSmall).invokeContinuation(fail);
+ if (!typeSystem.isDefinitelyNonNegativeInt(index.type)) {
+ Primitive isTooSmall = cps.applyBuiltin(
+ BuiltinOperator.NumLt,
+ <Primitive>[index, cps.makeZero()]);
+ cps.ifTruthy(isTooSmall).invokeContinuation(fail);
+ }
Primitive isTooLarge = cps.applyBuiltin(
BuiltinOperator.NumGe,
<Primitive>[index, cps.letPrim(new GetLength(list))]);
@@ -1220,65 +1308,56 @@
/// Tries to replace [node] with a direct `length` or index access.
///
/// Returns `true` if the node was replaced.
- bool specializeIndexableAccess(InvokeMethod node) {
- Primitive receiver = getDartReceiver(node);
- AbstractValue receiverValue = getValue(receiver);
+ specializeIndexableAccess(InvokeMethod node) {
+ Primitive receiver = node.dartReceiver;
+ AbstractConstantValue receiverValue = getValue(receiver);
if (!typeSystem.isDefinitelyIndexable(receiverValue.type,
allowNull: true)) {
- return false;
+ return null;
}
SourceInformation sourceInfo = node.sourceInformation;
- Continuation cont = node.continuation.definition;
switch (node.selector.name) {
case 'length':
- if (!node.selector.isGetter) return false;
- CpsFragment cps = new CpsFragment(sourceInfo);
- cps.invokeContinuation(cont, [cps.letPrim(new GetLength(receiver))]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ if (!node.selector.isGetter) return null;
+ return new GetLength(receiver);
case '[]':
- Primitive index = getDartArgument(node, 0);
- if (!lattice.isDefinitelyInt(getValue(index))) return false;
+ Primitive index = node.dartArgument(0);
+ if (!lattice.isDefinitelyInt(getValue(index))) return null;
CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
GetIndex get = cps.letPrim(new GetIndex(receiver, index));
- cps.invokeContinuation(cont, [get]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ node.replaceUsesWith(get);
+ // TODO(asgerf): Make replaceUsesWith set the hint?
+ get.hint = node.hint;
+ return cps;
case '[]=':
if (!typeSystem.isDefinitelyMutableIndexable(receiverValue.type,
allowNull: true)) {
- return false;
+ return null;
}
- Primitive index = getDartArgument(node, 0);
- Primitive value = getDartArgument(node, 1);
- if (!lattice.isDefinitelyInt(getValue(index))) return false;
+ Primitive index = node.dartArgument(0);
+ Primitive value = node.dartArgument(1);
+ if (!lattice.isDefinitelyInt(getValue(index))) return null;
CpsFragment cps = makeBoundsCheck(receiver, index, sourceInfo);
cps.letPrim(new SetIndex(receiver, index, value));
- assert(cont.parameters.single.hasNoUses);
- cont.parameters.clear();
- cps.invokeContinuation(cont, []);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ assert(node.hasNoUses);
+ return cps;
default:
- return false;
+ return null;
}
}
/// Tries to replace [node] with one or more direct array access operations.
///
/// Returns `true` if the node was replaced.
- bool specializeArrayAccess(InvokeMethod node) {
- Primitive list = getDartReceiver(node);
- AbstractValue listValue = getValue(list);
+ CpsFragment specializeArrayAccess(InvokeMethod node) {
+ Primitive list = node.dartReceiver;
+ AbstractConstantValue listValue = getValue(list);
// Ensure that the object is a native list or null.
if (!lattice.isDefinitelyArray(listValue, allowNull: true)) {
- return false;
+ return null;
}
bool isFixedLength =
lattice.isDefinitelyFixedArray(listValue, allowNull: true);
@@ -1287,31 +1366,30 @@
bool isExtendable =
lattice.isDefinitelyExtendableArray(listValue, allowNull: true);
SourceInformation sourceInfo = node.sourceInformation;
- Continuation cont = node.continuation.definition;
switch (node.selector.name) {
case 'add':
if (!node.selector.isCall ||
node.selector.positionalArgumentCount != 1 ||
node.selector.namedArgumentCount != 0) {
- return false;
+ return null;
}
- if (!isExtendable) return false;
- Primitive addedItem = getDartArgument(node, 0);
+ if (!isExtendable) return null;
+ Primitive addedItem = node.dartArgument(0);
CpsFragment cps = new CpsFragment(sourceInfo);
cps.invokeBuiltin(BuiltinMethod.Push,
list,
<Primitive>[addedItem]);
- cps.invokeContinuation(cont, [cps.makeNull()]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ if (node.hasAtLeastOneUse) {
+ node.replaceUsesWith(cps.makeNull());
+ }
+ return cps;
case 'removeLast':
if (!node.selector.isCall ||
node.selector.argumentCount != 0) {
- return false;
+ return null;
}
- if (!isExtendable) return false;
+ if (!isExtendable) return null;
CpsFragment cps = new CpsFragment(sourceInfo);
Primitive length = cps.letPrim(new GetLength(list));
Primitive isEmpty = cps.applyBuiltin(
@@ -1324,86 +1402,86 @@
Primitive removedItem = cps.invokeBuiltin(BuiltinMethod.Pop,
list,
<Primitive>[]);
- cps.invokeContinuation(cont, [removedItem]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ removedItem.hint = node.hint;
+ node.replaceUsesWith(removedItem);
+ return cps;
case 'addAll':
if (!node.selector.isCall ||
node.selector.argumentCount != 1) {
- return false;
+ return null;
}
- if (!isExtendable) return false;
- Primitive addedList = getDartArgument(node, 0);
- // Rewrite addAll([x1, ..., xN]) to push(x1, ..., xN).
+ if (!isExtendable) return null;
+ Primitive addedList = node.dartArgument(0);
+ // Rewrite addAll([x1, ..., xN]) to push(x1), ..., push(xN).
// Ensure that the list is not mutated between creation and use.
// We aim for the common case where this is the only use of the list,
// which also guarantees that this list is not mutated before use.
if (addedList is! LiteralList || !addedList.hasExactlyOneUse) {
- return false;
+ return null;
}
LiteralList addedLiteral = addedList;
CpsFragment cps = new CpsFragment(sourceInfo);
- cps.invokeBuiltin(BuiltinMethod.Push,
- list,
- addedLiteral.values.map((ref) => ref.definition).toList());
- cps.invokeContinuation(cont, [cps.makeNull()]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ for (Reference value in addedLiteral.values) {
+ cps.invokeBuiltin(BuiltinMethod.Push,
+ list,
+ <Primitive>[value.definition]);
+ }
+ if (node.hasAtLeastOneUse) {
+ node.replaceUsesWith(cps.makeNull());
+ }
+ return cps;
case 'elementAt':
if (!node.selector.isCall ||
node.selector.positionalArgumentCount != 1 ||
node.selector.namedArgumentCount != 0) {
- return false;
+ return null;
}
- if (listValue.isNullable) return false;
- Primitive index = getDartArgument(node, 0);
- if (!lattice.isDefinitelyInt(getValue(index))) return false;
+ if (listValue.isNullable) return null;
+ Primitive index = node.dartArgument(0);
+ if (!lattice.isDefinitelyInt(getValue(index))) return null;
CpsFragment cps = makeBoundsCheck(list, index, sourceInfo);
GetIndex get = cps.letPrim(new GetIndex(list, index));
- cps.invokeContinuation(cont, [get]);
- replaceSubtree(node, cps.result);
- push(cps.result);
- return true;
+ get.hint = node.hint;
+ node.replaceUsesWith(get);
+ return cps;
case 'forEach':
Element element =
compiler.world.locateSingleElement(node.selector, listValue.type);
if (element == null ||
!element.isFunction ||
- !node.selector.isCall) return false;
+ !node.selector.isCall) return null;
assert(node.selector.positionalArgumentCount == 1);
assert(node.selector.namedArgumentCount == 0);
FunctionDefinition target = functionCompiler.compileToCpsIr(element);
- node.receiver.definition.substituteFor(target.thisParameter);
- for (int i = 0; i < node.arguments.length; ++i) {
- node.arguments[i].definition.substituteFor(target.parameters[i]);
- }
- node.continuation.definition.substituteFor(target.returnContinuation);
-
- replaceSubtree(node, target.body);
- push(target.body);
- return true;
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive result = cps.inlineFunction(target,
+ node.receiver.definition,
+ node.arguments.map((ref) => ref.definition).toList(),
+ hint: node.hint);
+ node.replaceUsesWith(result);
+ return cps;
case 'iterator':
- if (!node.selector.isGetter) return false;
- Primitive iterator = cont.parameters.single;
- Continuation iteratorCont = cont;
+ // TODO(asgerf): This should be done differently.
+ // The types are recomputed in a very error-prone manner.
+ if (!node.selector.isGetter) return null;
+ Primitive iterator = node;
+ LetPrim iteratorBinding = node.parent;
// Check that all uses of the iterator are 'moveNext' and 'current'.
assert(!isInterceptedSelector(Selectors.moveNext));
assert(!isInterceptedSelector(Selectors.current));
for (Reference ref in iterator.effectiveUses) {
- if (ref.parent is! InvokeMethod) return false;
+ if (ref.parent is! InvokeMethod) return null;
InvokeMethod use = ref.parent;
- if (ref != use.receiver) return false;
+ if (ref != use.receiver) return null;
if (use.selector != Selectors.moveNext &&
use.selector != Selectors.current) {
- return false;
+ return null;
}
}
@@ -1416,17 +1494,14 @@
// Rewrite all uses of the iterator.
for (Reference ref in iterator.effectiveUses) {
InvokeMethod use = ref.parent;
- Continuation useCont = use.continuation.definition;
if (use.selector == Selectors.current) {
// Rewrite iterator.current to a use of the 'current' variable.
- Parameter result = useCont.parameters.single;
- if (result.hint != null) {
+ if (use.hint != null) {
// If 'current' was originally moved into a named variable, use
// that variable name for the mutable variable.
- current.hint = result.hint;
+ current.hint = use.hint;
}
- LetPrim let = makeLetPrimInvoke(new GetMutable(current), useCont);
- replaceSubtree(use, let);
+ use.replaceWith(new GetMutable(current));
} else {
assert (use.selector == Selectors.moveNext);
// Rewrite iterator.moveNext() to:
@@ -1444,6 +1519,8 @@
// [cps] contains the code we insert instead of moveNext().
CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Parameter result = new Parameter(node.hint);
+ Continuation moveNextCont = cps.letCont(<Parameter>[result]);
// We must check for concurrent modification when calling moveNext.
// When moveNext is used as a loop condition, the check prevents
@@ -1471,7 +1548,7 @@
//
// The check before the loop can often be eliminated because it
// follows immediately after the 'iterator' call.
- InteriorNode parent = getEffectiveParent(use);
+ InteriorNode parent = getEffectiveParent(use.parent);
if (!isFixedLength) {
if (parent is Continuation && parent.isRecursive) {
// Check for concurrent modification before every invocation
@@ -1482,7 +1559,7 @@
ref != null;
ref = ref.next) {
Expression invocationCaller = ref.parent;
- if (getEffectiveParent(invocationCaller) == iteratorCont) {
+ if (getEffectiveParent(invocationCaller) == iteratorBinding) {
// No need to check for concurrent modification immediately
// after the call to 'iterator'.
continue;
@@ -1506,18 +1583,25 @@
CpsFragment falseBranch = cps.ifFalsy(hasMore);
falseBranch
..setMutable(current, falseBranch.makeNull())
- ..invokeContinuation(useCont, [falseBranch.makeFalse()]);
+ ..invokeContinuation(moveNextCont, [falseBranch.makeFalse()]);
// Return true if there are more element.
+ current.type = typeSystem.elementTypeOfIndexable(listValue.type);
cps.setMutable(current,
cps.letPrim(new GetIndex(list, cps.getMutable(index))));
cps.setMutable(index, cps.applyBuiltin(
BuiltinOperator.NumAdd,
[cps.getMutable(index), cps.makeOne()]));
- cps.invokeContinuation(useCont, [cps.makeTrue()]);
+ cps.invokeContinuation(moveNextCont, [cps.makeTrue()]);
+
+ reanalyzeFragment(cps);
// Replace the moveNext() call. It will be visited later.
- replaceSubtree(use, cps.result);
+ LetPrim let = use.parent;
+ cps.context = moveNextCont;
+ cps.insertBelow(let);
+ let.remove();
+ use..replaceUsesWith(result)..destroy();
}
}
@@ -1529,38 +1613,13 @@
cps.letMutable(index, cps.makeZero());
cps.letMutable(current, cps.makeNull());
cps.letPrim(originalLength);
-
- // Insert this fragment before the continuation body and replace the
- // iterator call with a call to the continuation without arguments.
- // For scoping reasons, the variables must be bound inside the
- // continuation, not at the invocation-site.
- iteratorCont.parameters.clear();
- insertBefore(iteratorCont.body, cps);
- InvokeContinuation invoke = new InvokeContinuation(iteratorCont, []);
- replaceSubtree(node, invoke);
- push(invoke);
- return true;
+ return cps;
default:
- return false;
+ return null;
}
}
- /// If [prim] is the parameter to a call continuation, returns the
- /// corresponding call.
- CallExpression getCallWithResult(Primitive prim) {
- if (prim is Parameter && prim.parent is Continuation) {
- Continuation cont = prim.parent;
- if (cont.hasExactlyOneUse) {
- Node use = cont.firstRef.parent;
- if (use is CallExpression) {
- return use;
- }
- }
- }
- return null;
- }
-
/// Returns the first parent of [node] that is not a pure expression.
InteriorNode getEffectiveParent(Expression node) {
while (true) {
@@ -1582,14 +1641,14 @@
/// =>
/// obj.foo$<n>(<args>)
///
- bool specializeClosureCall(InvokeMethod node) {
+ Primitive specializeClosureCall(InvokeMethod node) {
Selector call = node.selector;
- if (!call.isClosureCall) return false;
+ if (!call.isClosureCall) return null;
assert(!isInterceptedSelector(call));
assert(call.argumentCount == node.arguments.length);
- Primitive tearOff = node.receiver.definition.effectiveDefinition;
+ Primitive tearOff = node.dartReceiver.effectiveDefinition;
// Note: We don't know if [tearOff] is actually a tear-off.
// We name variables based on the pattern we are trying to match.
@@ -1598,69 +1657,73 @@
FunctionSignature signature = target.functionSignature;
// If the selector does not apply, don't bother (will throw at runtime).
- if (!call.signatureApplies(target)) return false;
+ if (!call.signatureApplies(target)) return null;
// If some optional arguments are missing, give up.
// TODO(asgerf): Improve optimization by inserting default arguments.
- if (call.argumentCount != signature.parameterCount) return false;
+ if (call.argumentCount != signature.parameterCount) return null;
- InvokeStatic invoke = new InvokeStatic.byReference(
- target,
+ // Replace with InvokeStatic.
+ // The tear-off will be cleaned up by shrinking reductions.
+ return new InvokeStatic(target,
new Selector.fromElement(target),
- node.arguments,
- node.continuation,
+ node.arguments.map((ref) => ref.definition).toList(),
node.sourceInformation);
- node.receiver.unlink();
- replaceSubtree(node, invoke, unlink: false);
- push(invoke);
- return true;
}
- CallExpression tearOffInvoke = getCallWithResult(tearOff);
- if (tearOffInvoke is InvokeMethod && tearOffInvoke.selector.isGetter) {
- Selector getter = tearOffInvoke.selector;
+ if (tearOff is InvokeMethod && tearOff.selector.isGetter) {
+ Selector getter = tearOff.selector;
// TODO(asgerf): Support torn-off intercepted methods.
- if (isInterceptedSelector(getter)) return false;
+ if (isInterceptedSelector(getter)) return null;
- Continuation getterCont = tearOffInvoke.continuation.definition;
+ LetPrim tearOffBinding = tearOff.parent;
- Primitive object = tearOffInvoke.receiver.definition;
+ Primitive object = tearOff.receiver.definition;
// Ensure that the object actually has a foo member, since we might
// otherwise alter a noSuchMethod call.
TypeMask type = getValue(object).type;
- if (typeSystem.needsNoSuchMethodHandling(type, getter)) return false;
+ if (typeSystem.needsNoSuchMethodHandling(type, getter)) return null;
- // Determine if the getter invocation can have side-effects.
Element element = typeSystem.locateSingleElement(type, getter);
+
+ // If it's definitely not a tear-off, the rewrite is not worth it.
+ // If we don't know what the target is, we assume that it's better to
+ // rewrite (as long as it's safe to do so).
+ if (element != null && element.isGetter) return null;
+
+ // Either the target is a tear-off or we don't know what it is.
+ // If we don't know for sure, the getter might have side effects, which
+ // can make the rewriting unsafe, because we risk suppressing side effects
+ // in the getter.
+ // Determine if the getter invocation can have side-effects.
bool isPure = element != null && !element.isGetter;
// If there are multiple uses, we cannot eliminate the getter call and
// therefore risk duplicating its side effects.
- if (!isPure && tearOff.hasMultipleEffectiveUses) return false;
+ if (!isPure && tearOff.hasMultipleEffectiveUses) return null;
- // If the getter call is impure, we risk reordering side effects.
- if (!isPure && getEffectiveParent(node) != getterCont) {
- return false;
+ // If the getter call is impure, we risk reordering side effects,
+ // unless it is immediately prior to the closure call.
+ if (!isPure && getEffectiveParent(node.parent) != tearOffBinding) {
+ return null;
}
- InvokeMethod invoke = new InvokeMethod.byReference(
- new Reference<Primitive>(object),
+ InvokeMethod invoke = new InvokeMethod(
+ object,
new Selector.call(getter.memberName, call.callStructure),
type,
- node.arguments,
- node.continuation,
+ node.arguments.map((ref) => ref.definition).toList(),
node.sourceInformation);
- node.receiver.unlink();
- replaceSubtree(node, invoke, unlink: false);
+ node.receiver.changeTo(new Parameter(null)); // Remove the tear off use.
if (tearOff.hasNoEffectiveUses) {
// Eliminate the getter call if it has no more uses.
// This cannot be delegated to other optimizations because we need to
// avoid duplication of side effects.
destroyRefinementsOfDeadPrimitive(tearOff);
- getterCont.parameters.clear();
- replaceSubtree(tearOffInvoke, new InvokeContinuation(getterCont, []));
+ tearOff.destroy();
+ tearOffBinding.remove();
} else {
// There are more uses, so we cannot eliminate the getter call. This
// means we duplicated the effects of the getter call, but we should
@@ -1668,10 +1731,9 @@
assert(isPure);
}
- push(invoke);
- return true;
+ return invoke;
}
- return false;
+ return null;
}
void destroyRefinementsOfDeadPrimitive(Primitive prim) {
@@ -1688,39 +1750,39 @@
/// Inlines a single-use closure if it leaves the closure object with only
/// field accesses. This is optimized later by [ScalarReplacer].
- bool specializeSingleUseClosureCall(InvokeMethod node) {
+ CpsFragment specializeSingleUseClosureCall(InvokeMethod node) {
Selector call = node.selector;
- if (!call.isClosureCall) return false;
+ if (!call.isClosureCall) return null;
assert(!isInterceptedSelector(call));
assert(call.argumentCount == node.arguments.length);
Primitive receiver = node.receiver.definition;
- if (receiver is !CreateInstance) return false;
+ if (receiver is !CreateInstance) return null;
CreateInstance createInstance = receiver;
- if (!createInstance.hasExactlyOneUse) return false;
+ if (!createInstance.hasExactlyOneUse) return null;
// Inline only closures. This avoids inlining the 'call' method of a class
// that has many allocation sites.
- if (createInstance.classElement is !ClosureClassElement) return false;
+ if (createInstance.classElement is !ClosureClassElement) return null;
ClosureClassElement closureClassElement = createInstance.classElement;
Element element = closureClassElement.localLookup(Identifiers.call);
- if (element == null || !element.isFunction) return false;
+ if (element == null || !element.isFunction) return null;
FunctionElement functionElement = element;
- if (functionElement.asyncMarker != AsyncMarker.SYNC) return false;
+ if (functionElement.asyncMarker != AsyncMarker.SYNC) return null;
- if (!call.signatureApplies(functionElement)) return false;
+ if (!call.signatureApplies(functionElement)) return null;
// Inline only for exact match.
// TODO(sra): Handle call with defaulted arguments.
Selector targetSelector = new Selector.fromElement(functionElement);
- if (call.callStructure != targetSelector.callStructure) return false;
+ if (call.callStructure != targetSelector.callStructure) return null;
// Don't inline if [target] contains try-catch or try-finally. JavaScript
// engines typically do poor optimization of the entire function containing
// the 'try'.
- if (functionElement.resolvedAst.elements.containsTryStatement) return false;
+ if (functionElement.resolvedAst.elements.containsTryStatement) return null;
FunctionDefinition target =
functionCompiler.compileToCpsIr(functionElement);
@@ -1736,53 +1798,34 @@
// Closures do not currently have writable fields, but closure conversion
// could esily be changed to allocate some cells in a closure object.
if (use is SetField && ref == use.object) continue;
- return false;
+ return null;
}
- node.receiver.definition.substituteFor(target.thisParameter);
- for (int i = 0; i < node.arguments.length; ++i) {
- node.arguments[i].definition.substituteFor(target.parameters[i]);
- }
- node.continuation.definition.substituteFor(target.returnContinuation);
-
- replaceSubtree(node, target.body);
- push(target.body);
- return true;
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive returnValue = cps.inlineFunction(target,
+ node.receiver.definition,
+ node.arguments.map((ref) => ref.definition).toList(),
+ hint: node.hint);
+ node.replaceUsesWith(returnValue);
+ return cps;
}
- /// Side-effect free expressions with constant results are be replaced by:
- ///
- /// (LetPrim p = constant (InvokeContinuation k p)).
- ///
- /// The new expression will be visited.
- ///
- /// Returns true if the node was replaced.
- bool constifyExpression(CallExpression node) {
- Continuation continuation = node.continuation.definition;
- ConstantValue constant = replacements[node];
- if (constant == null) return false;
- Constant primitive = makeConstantPrimitive(constant);
- LetPrim letPrim = makeLetPrimInvoke(primitive, continuation);
- replaceSubtree(node, letPrim);
- push(letPrim);
- return true;
- }
-
- void visitInvokeMethod(InvokeMethod node) {
- if (constifyExpression(node)) return;
- if (specializeOperatorCall(node)) return;
- if (specializeFieldAccess(node)) return;
- if (specializeIndexableAccess(node)) return;
- if (specializeArrayAccess(node)) return;
- if (specializeSingleUseClosureCall(node)) return;
- if (specializeClosureCall(node)) return;
+ visitInvokeMethod(InvokeMethod node) {
+ var specialized =
+ specializeOperatorCall(node) ??
+ specializeFieldAccess(node) ??
+ specializeIndexableAccess(node) ??
+ specializeArrayAccess(node) ??
+ specializeSingleUseClosureCall(node) ??
+ specializeClosureCall(node);
+ if (specialized != null) return specialized;
node.mask =
- typeSystem.intersection(node.mask, getValue(getDartReceiver(node)).type);
+ typeSystem.intersection(node.mask, getValue(node.dartReceiver).type);
- AbstractValue receiver = getValue(node.receiver.definition);
+ AbstractConstantValue receiver = getValue(node.receiver.definition);
- if (node.receiverIsIntercepted &&
+ if (node.callingConvention == CallingConvention.Intercepted &&
node.receiver.definition.sameValue(node.arguments[0].definition)) {
// The receiver and first argument are the same; that means we already
// determined in visitInterceptor that we are targeting a non-interceptor.
@@ -1802,81 +1845,48 @@
// Replace the extra receiver argument with a dummy value if the
// target definitely does not use it.
Constant dummy = makeConstantPrimitive(new IntConstantValue(0));
- insertLetPrim(node, dummy);
+ new LetPrim(dummy).insertAbove(node.parent);
node.arguments[0].changeTo(dummy);
- node.receiverIsIntercepted = false;
+ node.callingConvention = CallingConvention.DummyIntercepted;
}
}
}
- void visitTypeCast(TypeCast node) {
- Continuation cont = node.continuation.definition;
-
- AbstractValue value = getValue(node.value.definition);
+ CpsFragment visitTypeCast(TypeCast node) {
+ AbstractConstantValue value = getValue(node.value.definition);
switch (lattice.isSubtypeOf(value, node.dartType, allowNull: true)) {
case AbstractBool.Maybe:
case AbstractBool.Nothing:
- break;
+ return null;
case AbstractBool.True:
- // Cast always succeeds, replace it with InvokeContinuation.
- InvokeContinuation invoke =
- new InvokeContinuation(cont, <Primitive>[node.value.definition]);
- replaceSubtree(node, invoke);
- push(invoke);
- return;
+ // Return an unused primitive moved again.
+ node.replaceUsesWith(node.value.definition);
+ return new CpsFragment(); // Remove the node.
case AbstractBool.False:
- // Cast always fails, remove unreachable continuation body.
- replaceSubtree(cont.body, new Unreachable());
- break;
+ // Note: The surrounding LetPrim will remove the following code because
+ // it always throws. We don't need to do it here.
+ return null;
}
}
/// Specialize calls to internal static methods.
- ///
- /// Returns true if the call was replaced.
- bool specializeInternalMethodCall(InvokeStatic node) {
- // TODO(asgerf): This is written to easily scale to more cases,
- // either add more cases or clean up.
- Continuation cont = node.continuation.definition;
- Primitive arg(int n) => node.arguments[n].definition;
- AbstractValue argType(int n) => getValue(arg(n));
-
- bool replaceWithBinary(BuiltinOperator operator,
- Primitive left,
- Primitive right) {
- Primitive prim =
- new ApplyBuiltinOperator(operator, <Primitive>[left, right],
- node.sourceInformation);
- LetPrim let = makeLetPrimInvoke(prim, cont);
- replaceSubtree(node, let);
- push(let);
- return true; // So returning early is more convenient.
- }
-
- if (node.target.library.isInternalLibrary) {
- switch(node.target.name) {
- case InternalMethod.Stringify:
- if (lattice.isDefinitelyString(argType(0))) {
- InvokeContinuation invoke =
- new InvokeContinuation(cont, <Primitive>[arg(0)]);
- replaceSubtree(node, invoke);
- push(invoke);
- return true;
- }
- break;
+ specializeInternalMethodCall(InvokeStatic node) {
+ if (node.target == backend.helpers.stringInterpolationHelper) {
+ AbstractConstantValue value = getValue(node.arguments[0].definition);
+ if (lattice.isDefinitelyString(value)) {
+ node.replaceUsesWith(node.arguments[0].definition);
+ return new CpsFragment();
}
- } else if (node.target.library.isDartCore) {
- switch(node.target.name) {
- case CorelibMethod.Identical:
- if (node.arguments.length == 2) {
- return replaceWithBinary(BuiltinOperator.Identical, arg(0), arg(1));
- }
- break;
+ } else if (node.target == compiler.identicalFunction) {
+ if (node.arguments.length == 2) {
+ return new ApplyBuiltinOperator(BuiltinOperator.Identical,
+ [node.arguments[0].definition, node.arguments[1].definition],
+ node.sourceInformation);
}
}
- return false;
+ return null;
}
/// Try to inline static invocations.
@@ -1886,13 +1896,13 @@
///
/// * Inline functions with a single expression statement or return statement
/// provided that the subexpression is an invocation of foreign code.
- bool inlineInvokeStatic(InvokeStatic node) {
+ inlineInvokeStatic(InvokeStatic node) {
// The target might not have an AST, for example if it deferred.
- if (!node.target.hasNode) return false;
+ if (!node.target.hasNode) return null;
if (node.target.asyncMarker != AsyncMarker.SYNC) {
// Inlining of async/sync*/async* methods is currently not supported.
- return false;
+ return null;
}
// True if an expression is non-expansive, in the sense defined by this
@@ -1952,46 +1962,48 @@
return false;
}
- if (!shouldInline()) return false;
+ if (!shouldInline()) return null;
FunctionDefinition target = functionCompiler.compileToCpsIr(node.target);
- for (int i = 0; i < node.arguments.length; ++i) {
- node.arguments[i].definition.substituteFor(target.parameters[i]);
- }
- node.continuation.definition.substituteFor(target.returnContinuation);
- replaceSubtree(node, target.body);
- push(target.body);
- return true;
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Primitive result = cps.inlineFunction(target,
+ null,
+ node.arguments.map((ref) => ref.definition).toList(),
+ hint: node.hint);
+ node.replaceUsesWith(result);
+ return cps;
}
- void visitInvokeStatic(InvokeStatic node) {
- if (constifyExpression(node)) return;
- if (specializeInternalMethodCall(node)) return;
- if (inlineInvokeStatic(node)) return;
+ visitInvokeStatic(InvokeStatic node) {
+ return specializeInternalMethodCall(node) ?? inlineInvokeStatic(node);
}
- AbstractValue getValue(Variable node) {
+ AbstractConstantValue getValue(Variable node) {
+ assert(node.type != null);
ConstantValue constant = values[node];
if (constant != null) {
- return new AbstractValue.constantValue(constant, node.type);
+ return new AbstractConstantValue.constantValue(constant, node.type);
}
- if (node.type != null) {
- return new AbstractValue.nonConstant(node.type);
- }
- return lattice.nothing;
+ return new AbstractConstantValue.nonConstant(node.type);
}
/*************************** PRIMITIVES **************************/
//
- // The visit method for a primitive may optionally return a new
- // primitive. If non-null, the surrounding LetPrim will substitute it
- // and bind the new primitive instead.
+ // The visit method for a primitive may return one of the following:
+ // - Primitive:
+ // The visited primitive will be replaced by the returned primitive.
+ // The type of the primitive will be recomputed.
+ // - CpsFragment:
+ // The primitive binding will be destroyed and replaced by the given
+ // code fragment. All types in the fragment will be recomputed.
+ // - Null:
+ // Nothing happens. The primitive remains as it is.
//
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- ast.DartString getString(AbstractValue value) {
+ ast.DartString getString(AbstractConstantValue value) {
StringConstantValue constant = value.constant;
return constant.primitiveValue;
}
@@ -2002,9 +2014,11 @@
int i = 0;
while (i < node.arguments.length - 1) {
int startOfSequence = i;
- AbstractValue firstValue = getValue(node.arguments[i++].definition);
+ AbstractConstantValue firstValue =
+ getValue(node.arguments[i++].definition);
if (!firstValue.isConstant) continue;
- AbstractValue secondValue = getValue(node.arguments[i++].definition);
+ AbstractConstantValue secondValue =
+ getValue(node.arguments[i++].definition);
if (!secondValue.isConstant) continue;
ast.DartString string =
@@ -2014,14 +2028,15 @@
// We found a sequence of at least two constants.
// Look for the end of the sequence.
while (i < node.arguments.length) {
- AbstractValue value = getValue(node.arguments[i].definition);
+ AbstractConstantValue value =
+ getValue(node.arguments[i].definition);
if (!value.isConstant) break;
string = new ast.ConsDartString(string, getString(value));
++i;
}
Constant prim =
makeConstantPrimitive(new StringConstantValue(string));
- insertLetPrim(node.parent, prim);
+ new LetPrim(prim).insertAbove(node.parent);
for (int k = startOfSequence; k < i; ++k) {
node.arguments[k].unlink();
node.arguments[k] = null; // Remove the argument after the loop.
@@ -2040,19 +2055,19 @@
case BuiltinOperator.Identical:
Primitive leftArg = node.arguments[0].definition;
Primitive rightArg = node.arguments[1].definition;
- AbstractValue left = getValue(leftArg);
- AbstractValue right = getValue(rightArg);
+ AbstractConstantValue left = getValue(leftArg);
+ AbstractConstantValue right = getValue(rightArg);
if (lattice.isDefinitelyBool(left) &&
right.isConstant &&
right.constant.isTrue) {
// Replace identical(x, true) by x when x is known to be a boolean.
// Note that this is not safe if x is null, because the value might
- // not be used as a condition. A rule for [IsTrue] handles that case.
- leftArg.substituteFor(node);
+ // not be used as a condition.
+ node.replaceUsesWith(leftArg);
} else if (lattice.isDefinitelyBool(right) &&
left.isConstant &&
left.constant.isTrue) {
- rightArg.substituteFor(node);
+ node.replaceUsesWith(rightArg);
} else if (left.isNullConstant || right.isNullConstant) {
// Use `==` for comparing against null, so JS undefined and JS null
// are considered equal.
@@ -2081,52 +2096,21 @@
}
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- if (node.method == BuiltinMethod.Push) {
- // Convert consecutive pushes into a single push.
- InteriorNode parent = getEffectiveParent(node.parent);
- if (parent is LetPrim && parent.primitive is ApplyBuiltinMethod) {
- ApplyBuiltinMethod previous = parent.primitive;
- if (previous.method == BuiltinMethod.Push &&
- previous.receiver.definition.sameValue(node.receiver.definition)) {
- // We found two consecutive pushes.
- // Move all arguments from the first push onto the second one.
- List<Reference<Primitive>> arguments = previous.arguments;
- for (Reference ref in arguments) {
- ref.parent = node;
- }
- arguments.addAll(node.arguments);
- node.arguments = arguments;
- // Elimnate the old push.
- previous.receiver.unlink();
- assert(previous.hasNoUses);
- parent.parent.body = parent.body;
- parent.body.parent = parent.parent;
- }
- }
- }
}
- Primitive visitTypeTest(TypeTest node) {
+ visitTypeTest(TypeTest node) {
Primitive prim = node.value.definition;
Primitive unaryBuiltinOperator(BuiltinOperator operator) =>
new ApplyBuiltinOperator(
operator, <Primitive>[prim], node.sourceInformation);
- void unlinkInterceptor() {
- if (node.interceptor != null) {
- node.interceptor.unlink();
- node.interceptor = null;
- }
- }
-
- AbstractValue value = getValue(prim);
+ AbstractConstantValue value = getValue(prim);
types.DartType dartType = node.dartType;
if (!(dartType.isInterfaceType && dartType.isRaw)) {
// TODO(23685): Efficient function arity check.
// TODO(sra): Pass interceptor to runtime subtype functions.
- unlinkInterceptor();
return null;
}
@@ -2168,7 +2152,7 @@
// This has lower priority than the 'typeof'-based tests because
// 'typeof' expressions might give the VM some more useful information.
Primitive nullConst = makeConstantPrimitive(new NullConstantValue());
- insertLetPrim(node.parent, nullConst);
+ new LetPrim(nullConst).insertAbove(node.parent);
return new ApplyBuiltinOperator(
BuiltinOperator.LooseNeq,
<Primitive>[prim, nullConst],
@@ -2198,14 +2182,19 @@
if (dartType == dartTypes.coreTypes.stringType ||
dartType == dartTypes.coreTypes.boolType) {
// These types are recognized in tree_ir TypeOperator codegen.
- unlinkInterceptor();
return null;
}
- // TODO(sra): Propagate sourceInformation.
// TODO(sra): If getInterceptor(x) === x or JSNull, rewrite
// getInterceptor(x).$isFoo ---> x != null && x.$isFoo
- return new TypeTestViaFlag(node.interceptor.definition, dartType);
+ CpsFragment cps = new CpsFragment(node.sourceInformation);
+ Interceptor interceptor =
+ cps.letPrim(new Interceptor(prim, node.sourceInformation));
+ interceptor.interceptedClasses.addAll(backend.interceptedClasses);
+ Primitive testViaFlag =
+ cps.letPrim(new TypeTestViaFlag(interceptor, dartType));
+ node.replaceUsesWith(testViaFlag);
+ return cps;
}
Primitive visitTypeTestViaFlag(TypeTestViaFlag node) {
@@ -2213,7 +2202,7 @@
}
Primitive visitInterceptor(Interceptor node) {
- AbstractValue value = getValue(node.input.definition);
+ AbstractConstantValue value = getValue(node.input.definition);
TypeMask interceptedInputs = value.type.intersection(
typeSystem.interceptorType.nullable(), classWorld);
bool interceptNull =
@@ -2230,6 +2219,11 @@
node.interceptedClasses..clear()..add(helpers.jsNumberClass);
return;
}
+
+ // TODO(asgerf): Avoid adding non-instantiated intercepted classes
+ // in the first place. (This should also happen in later pass).
+ node.interceptedClasses.retainWhere(classWorld.isInstantiated);
+
TypeMask interceptedClassesType = new TypeMask.unionOf(
node.interceptedClasses.map(typeSystem.getInterceptorSubtypes),
classWorld);
@@ -2267,8 +2261,8 @@
//
// We only do this optimization if the resulting interceptor call is
// sufficiently specialized to be worth it (#classes <= 2).
- // TODO(asgerf): Reconsider when TypeTest interceptors don't intercept
- // ALL interceptor classes.
+ // TODO(asgerf): Reconsider when TypeTestViaFlag interceptors don't
+ // intercept ALL interceptor classes.
if (node.interceptedClasses.length > 1 &&
node.interceptedClasses.length < 4 &&
node.interceptedClasses.contains(helpers.jsInterceptorClass)) {
@@ -2290,7 +2284,7 @@
// Remove the interceptor call if it can only return its input.
if (node.interceptedClasses.isEmpty) {
- node.input.definition.substituteFor(node);
+ node.replaceUsesWith(node.input.definition);
return null;
}
@@ -2398,11 +2392,13 @@
World get classWorld => typeSystem.classWorld;
- AbstractValue get nothing => lattice.nothing;
+ AbstractConstantValue get nothing => lattice.nothing;
- AbstractValue nonConstant([TypeMask type]) => lattice.nonConstant(type);
+ AbstractConstantValue nonConstant([TypeMask type]) {
+ return lattice.nonConstant(type);
+ }
- AbstractValue constantValue(ConstantValue constant, [TypeMask type]) {
+ AbstractConstantValue constantValue(ConstantValue constant, [TypeMask type]) {
return lattice.constant(constant, type);
}
@@ -2410,13 +2406,8 @@
// Access through [getValue] and [setValue].
final Map<Variable, ConstantValue> values;
- /// Expressions that invoke their call continuation with a constant value
- /// and without any side effects. These can be replaced by the constant.
- final Map<Expression, ConstantValue> replacements;
-
TypePropagationVisitor(this.lattice,
this.values,
- this.replacements,
this.internalError);
void analyze(FunctionDefinition root) {
@@ -2472,13 +2463,13 @@
/// Returns the lattice value corresponding to [node], defaulting to nothing.
///
/// Never returns null.
- AbstractValue getValue(Variable node) {
+ AbstractConstantValue getValue(Variable node) {
ConstantValue constant = values[node];
if (constant != null) {
- return new AbstractValue.constantValue(constant, node.type);
+ return new AbstractConstantValue.constantValue(constant, node.type);
}
if (node.type != null) {
- return new AbstractValue.nonConstant(node.type);
+ return new AbstractConstantValue.nonConstant(node.type);
}
return lattice.nothing;
}
@@ -2486,9 +2477,9 @@
/// Joins the passed lattice [updateValue] to the current value of [node],
/// and adds it to the definition work set if it has changed and [node] is
/// a definition.
- void setValue(Variable node, AbstractValue updateValue) {
- AbstractValue oldValue = getValue(node);
- AbstractValue newValue = lattice.join(oldValue, updateValue);
+ void setValue(Variable node, AbstractConstantValue updateValue) {
+ AbstractConstantValue oldValue = getValue(node);
+ AbstractConstantValue newValue = lattice.join(oldValue, updateValue);
node.type = newValue.type; // Ensure type is initialized even if bottom.
if (oldValue == newValue) {
return;
@@ -2501,44 +2492,22 @@
defWorklist.add(node);
}
- /// Updates the value of a [CallExpression]'s continuation parameter.
- void setResult(CallExpression call,
- AbstractValue updateValue,
+ /// Sets the type of the given primitive.
+ ///
+ /// If [updateValue] is a constant and [canReplace] is true, the primitive
+ /// is also marked as safe for elimination, so it can be constant-folded.
+ void setResult(UnsafePrimitive prim,
+ AbstractConstantValue updateValue,
{bool canReplace: false}) {
- Continuation cont = call.continuation.definition;
- setValue(cont.parameters.single, updateValue);
- if (!updateValue.isNothing) {
- setReachable(cont);
-
- if (updateValue.isConstant && canReplace) {
- replacements[call] = updateValue.constant;
- } else {
- // A replacement might have been set in a previous iteration.
- replacements.remove(call);
- }
- }
+ // TODO(asgerf): Separate constant folding from side effect analysis.
+ setValue(prim, updateValue);
+ prim.isSafeForElimination = canReplace && updateValue.isConstant;
}
bool isInterceptedSelector(Selector selector) {
return backend.isInterceptedSelector(selector);
}
- Primitive getDartReceiver(InvokeMethod node) {
- if (node.receiverIsIntercepted) {
- return node.arguments[0].definition;
- } else {
- return node.receiver.definition;
- }
- }
-
- Primitive getDartArgument(InvokeMethod node, int n) {
- if (isInterceptedSelector(node.selector)) {
- return node.arguments[n+1].definition;
- } else {
- return node.arguments[n].definition;
- }
- }
-
// -------------------------- Visitor overrides ------------------------------
void visit(Node node) { node.accept(this); }
@@ -2559,14 +2528,20 @@
setValue(node.thisParameter,
nonConstant(typeSystem.getReceiverType(node.element)));
}
+ bool hasParameterWithoutValue = false;
for (Parameter param in node.parameters.skip(firstActualParameter)) {
// TODO(karlklose): remove reference to the element model.
TypeMask type = param.hint is ParameterElement
? typeSystem.getParameterType(param.hint)
: typeSystem.dynamicType;
setValue(param, lattice.fromMask(type));
+ if (type.isEmpty && !type.isNullable) {
+ hasParameterWithoutValue = true;
+ }
}
- push(node.body);
+ if (!hasParameterWithoutValue) { // Don't analyze unreachable code.
+ push(node.body);
+ }
}
void visitLetPrim(LetPrim node) {
@@ -2601,13 +2576,10 @@
}
void visitInvokeStatic(InvokeStatic node) {
- if (node.target.library != null && node.target.library.isInternalLibrary) {
- switch (node.target.name) {
- case InternalMethod.Stringify:
- AbstractValue argValue = getValue(node.arguments[0].definition);
- setResult(node, lattice.stringify(argValue), canReplace: true);
- return;
- }
+ if (node.target == backend.helpers.stringInterpolationHelper) {
+ AbstractConstantValue argValue = getValue(node.arguments[0].definition);
+ setResult(node, lattice.stringify(argValue), canReplace: true);
+ return;
}
TypeMask returnType = typeSystem.getReturnType(node.target);
@@ -2622,41 +2594,59 @@
// continuation. Note that this is effectively a phi node in SSA terms.
for (int i = 0; i < node.arguments.length; i++) {
Primitive def = node.arguments[i].definition;
- AbstractValue cell = getValue(def);
+ AbstractConstantValue cell = getValue(def);
setValue(cont.parameters[i], cell);
}
}
void visitInvokeMethod(InvokeMethod node) {
- AbstractValue receiver = getValue(node.receiver.definition);
+ AbstractConstantValue receiver = getValue(node.receiver.definition);
node.receiverIsNotNull = receiver.isDefinitelyNotNull;
if (receiver.isNothing) {
+ setResult(node, lattice.nothing);
return; // And come back later.
}
- // Constant fold known length of containers.
- if (node.selector == Selectors.length) {
- AbstractValue object = getValue(getDartReceiver(node));
- if (typeSystem.isDefinitelyIndexable(object.type, allowNull: true)) {
- int length = typeSystem.getContainerLength(object.type.nonNullable());
- if (length != null) {
- setResult(node, constantValue(new IntConstantValue(length)),
- canReplace: !object.isNullable);
+ if (node.selector.isGetter) {
+ // Constant fold known length of containers.
+ if (node.selector == Selectors.length) {
+ AbstractConstantValue object = getValue(node.dartReceiver);
+ if (typeSystem.isDefinitelyIndexable(object.type, allowNull: true)) {
+ AbstractConstantValue length = lattice.lengthSpecial(object);
+ if (length != null) {
+ setResult(node, length, canReplace: !object.isNullable);
+ }
}
}
+ setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
+ return;
+ }
+
+ if (node.selector.isCall) {
+ AbstractConstantValue result;
+ if (node.selector == Selectors.codeUnitAt) {
+ AbstractConstantValue object = getValue(node.dartReceiver);
+ AbstractConstantValue right = getValue(node.dartArgument(0));
+ result = lattice.codeUnitAtSpecial(object, right);
+ }
+ if (result == null) {
+ setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
+ } else {
+ setResult(node, result, canReplace: true);
+ }
+ return;
}
if (!node.selector.isOperator) {
- // TODO(jgruber): Handle known methods on constants such as String.length.
setResult(node, lattice.getInvokeReturnType(node.selector, node.mask));
return;
}
// Calculate the resulting constant if possible.
- AbstractValue result;
+ AbstractConstantValue result;
String opname = node.selector.name;
if (node.arguments.length == 1) {
- AbstractValue argument = getValue(getDartReceiver(node));
+ AbstractConstantValue argument = getValue(node.dartReceiver);
// Unary operator.
if (opname == "unary-") {
opname = "-";
@@ -2665,8 +2655,8 @@
result = lattice.unaryOp(operator, argument);
} else if (node.arguments.length == 2) {
// Binary operator.
- AbstractValue left = getValue(getDartReceiver(node));
- AbstractValue right = getValue(getDartArgument(node, 0));
+ AbstractConstantValue left = getValue(node.dartReceiver);
+ AbstractConstantValue right = getValue(node.dartArgument(0));
BinaryOperator operator = BinaryOperator.parse(opname);
result = lattice.binaryOp(operator, left, right);
}
@@ -2682,32 +2672,37 @@
void visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
- void unaryOp(AbstractValue operation(AbstractValue argument),
- TypeMask defaultType) {
- AbstractValue value = getValue(node.arguments[0].definition);
+ void unaryOp(
+ AbstractConstantValue operation(AbstractConstantValue argument),
+ TypeMask defaultType) {
+ AbstractConstantValue value = getValue(node.arguments[0].definition);
setValue(node, operation(value) ?? nonConstant(defaultType));
}
void binaryOp(
- AbstractValue operation(AbstractValue left, AbstractValue right),
+ AbstractConstantValue operation(AbstractConstantValue left,
+ AbstractConstantValue right),
TypeMask defaultType) {
- AbstractValue left = getValue(node.arguments[0].definition);
- AbstractValue right = getValue(node.arguments[1].definition);
+ AbstractConstantValue left = getValue(node.arguments[0].definition);
+ AbstractConstantValue right = getValue(node.arguments[1].definition);
setValue(node, operation(left, right) ?? nonConstant(defaultType));
}
void binaryNumOp(
- AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ AbstractConstantValue operation(AbstractConstantValue left,
+ AbstractConstantValue right)) {
binaryOp(operation, typeSystem.numType);
}
void binaryUint32Op(
- AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ AbstractConstantValue operation(AbstractConstantValue left,
+ AbstractConstantValue right)) {
binaryOp(operation, typeSystem.uint32Type);
}
void binaryBoolOp(
- AbstractValue operation(AbstractValue left, AbstractValue right)) {
+ AbstractConstantValue operation(AbstractConstantValue left,
+ AbstractConstantValue right)) {
binaryOp(operation, typeSystem.boolType);
}
@@ -2715,8 +2710,9 @@
case BuiltinOperator.StringConcatenate:
ast.DartString stringValue = const ast.LiteralDartString('');
for (Reference<Primitive> arg in node.arguments) {
- AbstractValue value = getValue(arg.definition);
+ AbstractConstantValue value = getValue(arg.definition);
if (value.isNothing) {
+ setValue(node, lattice.nothing);
return; // And come back later
} else if (value.isConstant &&
value.constant.isString &&
@@ -2736,16 +2732,22 @@
}
break;
+ case BuiltinOperator.CharCodeAt:
+ binaryOp(lattice.codeUnitAtSpecial, typeSystem.uint31Type);
+ break;
+
case BuiltinOperator.Identical:
case BuiltinOperator.StrictEq:
case BuiltinOperator.LooseEq:
- AbstractValue leftConst = getValue(node.arguments[0].definition);
- AbstractValue rightConst = getValue(node.arguments[1].definition);
+ AbstractConstantValue leftConst =
+ getValue(node.arguments[0].definition);
+ AbstractConstantValue rightConst =
+ getValue(node.arguments[1].definition);
ConstantValue leftValue = leftConst.constant;
ConstantValue rightValue = rightConst.constant;
if (leftConst.isNothing || rightConst.isNothing) {
- // Come back later.
- return;
+ setValue(node, lattice.nothing);
+ return; // And come back later.
} else if (!leftConst.isConstant || !rightConst.isConstant) {
TypeMask leftType = leftConst.type;
TypeMask rightType = rightConst.type;
@@ -2857,7 +2859,7 @@
}
void visitApplyBuiltinMethod(ApplyBuiltinMethod node) {
- AbstractValue receiver = getValue(node.receiver.definition);
+ AbstractConstantValue receiver = getValue(node.receiver.definition);
if (node.method == BuiltinMethod.Pop) {
setValue(node, nonConstant(
typeSystem.elementTypeOfIndexable(receiver.type)));
@@ -2889,7 +2891,7 @@
}
void visitBranch(Branch node) {
- AbstractValue conditionCell = getValue(node.condition.definition);
+ AbstractConstantValue conditionCell = getValue(node.condition.definition);
AbstractBool boolifiedValue = node.isStrictCheck
? lattice.strictBoolify(conditionCell)
: lattice.boolify(conditionCell);
@@ -2922,7 +2924,7 @@
}
void handleTypeTest(
- Primitive node, AbstractValue input, types.DartType dartType) {
+ Primitive node, AbstractConstantValue input, types.DartType dartType) {
TypeMask boolType = typeSystem.boolType;
switch(lattice.isSubtypeOf(input, dartType, allowNull: false)) {
case AbstractBool.Nothing:
@@ -2943,27 +2945,26 @@
}
void visitTypeCast(TypeCast node) {
- Continuation cont = node.continuation.definition;
- AbstractValue input = getValue(node.value.definition);
+ AbstractConstantValue input = getValue(node.value.definition);
switch (lattice.isSubtypeOf(input, node.dartType, allowNull: true)) {
case AbstractBool.Nothing:
+ setValue(node, lattice.nothing);
break; // And come back later.
case AbstractBool.True:
- setReachable(cont);
- setValue(cont.parameters.single, input);
+ setValue(node, input);
break;
case AbstractBool.False:
- break; // Cast fails. Continuation should remain unreachable.
+ setValue(node, lattice.nothing); // Cast fails.
+ break;
case AbstractBool.Maybe:
- setReachable(cont);
// Narrow type of output to those that survive the cast.
TypeMask type = input.type.intersection(
typeSystem.subtypesOf(node.dartType).nullable(),
classWorld);
- setValue(cont.parameters.single, nonConstant(type));
+ setValue(node, nonConstant(type));
break;
}
}
@@ -2996,10 +2997,6 @@
}
}
- void visitCreateFunction(CreateFunction node) {
- throw 'CreateFunction is not used';
- }
-
void visitGetMutable(GetMutable node) {
setValue(node, getValue(node.variable.definition));
}
@@ -3034,7 +3031,7 @@
void visitInterceptor(Interceptor node) {
push(node.input.definition);
- AbstractValue value = getValue(node.input.definition);
+ AbstractConstantValue value = getValue(node.input.definition);
if (value.isNothing) {
setValue(node, nothing);
} else if (value.isNullable &&
@@ -3050,8 +3047,13 @@
}
void visitGetField(GetField node) {
- node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
- setValue(node, lattice.fromMask(typeSystem.getFieldType(node.field)));
+ AbstractConstantValue object = getValue(node.object.definition);
+ if (object.isNothing || object.isNullConstant) {
+ setValue(node, nothing);
+ } else {
+ node.objectIsNotNull = object.isDefinitelyNotNull;
+ setValue(node, lattice.fromMask(typeSystem.getFieldType(node.field)));
+ }
}
void visitSetField(SetField node) {}
@@ -3061,7 +3063,8 @@
}
void visitCreateInstance(CreateInstance node) {
- setValue(node, nonConstant(typeSystem.nonNullExact(node.classElement.declaration)));
+ setValue(node,
+ nonConstant(typeSystem.nonNullExact(node.classElement.declaration)));
}
void visitReifyRuntimeType(ReifyRuntimeType node) {
@@ -3088,20 +3091,18 @@
@override
void visitForeignCode(ForeignCode node) {
- if (node.continuation != null) {
- setResult(node, nonConstant(node.type));
- }
+ setValue(node, nonConstant(node.type));
}
@override
void visitGetLength(GetLength node) {
- AbstractValue input = getValue(node.object.definition);
- node.objectIsNotNull = getValue(node.object.definition).isDefinitelyNotNull;
- int length = typeSystem.getContainerLength(input.type);
+ AbstractConstantValue input = getValue(node.object.definition);
+ node.objectIsNotNull = input.isDefinitelyNotNull;
+ AbstractConstantValue length = lattice.lengthSpecial(input);
if (length != null) {
// TODO(asgerf): Constant-folding the length might degrade the VM's
// own bounds-check elimination?
- setValue(node, constantValue(new IntConstantValue(length)));
+ setValue(node, length);
} else {
setValue(node, nonConstant(typeSystem.uint32Type));
}
@@ -3109,14 +3110,17 @@
@override
void visitGetIndex(GetIndex node) {
- AbstractValue input = getValue(node.object.definition);
- setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(input.type)));
+ AbstractConstantValue object = getValue(node.object.definition);
+ if (object.isNothing || object.isNullConstant) {
+ setValue(node, nothing);
+ } else {
+ node.objectIsNotNull = object.isDefinitelyNotNull;
+ setValue(node, nonConstant(typeSystem.elementTypeOfIndexable(object.type)));
+ }
}
@override
- void visitSetIndex(SetIndex node) {
- setValue(node, nonConstant());
- }
+ void visitSetIndex(SetIndex node) {}
@override
void visitAwait(Await node) {
@@ -3125,12 +3129,12 @@
@override
visitYield(Yield node) {
- setReachable(node.continuation.definition);
+ setValue(node, nonConstant());
}
@override
void visitRefinement(Refinement node) {
- AbstractValue value = getValue(node.value.definition);
+ AbstractConstantValue value = getValue(node.value.definition);
if (value.isNothing ||
typeSystem.areDisjoint(value.type, node.refineType)) {
setValue(node, nothing);
@@ -3152,7 +3156,7 @@
/// CONSTANT: is a constant. The value is stored in the [constant] field,
/// and the type of the constant is in the [type] field.
/// NONCONST: not a constant, but [type] may hold some information.
-class AbstractValue {
+class AbstractConstantValue {
static const int NOTHING = 0;
static const int CONSTANT = 1;
static const int NONCONST = 2;
@@ -3161,25 +3165,26 @@
final ConstantValue constant;
final TypeMask type;
- AbstractValue._internal(this.kind, this.constant, this.type) {
+ AbstractConstantValue._internal(this.kind, this.constant, this.type) {
assert(kind != CONSTANT || constant != null);
assert(constant is! SyntheticConstantValue);
}
- AbstractValue.nothing()
+ AbstractConstantValue.nothing()
: this._internal(NOTHING, null, new TypeMask.nonNullEmpty());
- AbstractValue.constantValue(ConstantValue constant, TypeMask type)
+ AbstractConstantValue.constantValue(ConstantValue constant, TypeMask type)
: this._internal(CONSTANT, constant, type);
- factory AbstractValue.nonConstant(TypeMask type) {
+ factory AbstractConstantValue.nonConstant(TypeMask type) {
if (type.isEmpty) {
if (type.isNullable)
- return new AbstractValue.constantValue(new NullConstantValue(), type);
+ return new AbstractConstantValue.constantValue(
+ new NullConstantValue(), type);
else
- return new AbstractValue.nothing();
+ return new AbstractConstantValue.nothing();
} else {
- return new AbstractValue._internal(NONCONST, null, type);
+ return new AbstractConstantValue._internal(NONCONST, null, type);
}
}
@@ -3198,7 +3203,7 @@
return hash & 0x3fffffff;
}
- bool operator ==(AbstractValue that) {
+ bool operator ==(AbstractConstantValue that) {
return that.kind == this.kind &&
that.constant == this.constant &&
that.type == this.type;
@@ -3215,16 +3220,6 @@
}
}
-/// Enum-like class with the names of internal methods we care about.
-abstract class InternalMethod {
- static const String Stringify = 'S';
-}
-
-/// Enum-like class with the names of dart:core methods we care about.
-abstract class CorelibMethod {
- static const String Identical = 'identical';
-}
-
/// Suggested name for a synthesized loop index.
class LoopIndexEntity extends Entity {
String get name => 'i';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index fa7aeb7..662316b 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -119,6 +119,7 @@
bool dumpInfo = false;
bool allowNativeExtensions = false;
bool trustTypeAnnotations = false;
+ bool trustJSInteropTypeAnnotations = false;
bool checkedMode = false;
// List of provided options that imply that output is expected.
List<String> optionsImplyCompilation = <String>[];
@@ -227,6 +228,11 @@
implyCompilation(argument);
}
+ setTrustJSInteropTypeAnnotations(String argument) {
+ trustJSInteropTypeAnnotations = true;
+ implyCompilation(argument);
+ }
+
setTrustPrimitives(String argument) {
implyCompilation(argument);
}
@@ -326,6 +332,9 @@
new OptionHandler(Flags.trustPrimitives,
(_) => setTrustPrimitives(
Flags.trustPrimitives)),
+ new OptionHandler(Flags.trustJSInteropTypeAnnotations,
+ (_) => setTrustJSInteropTypeAnnotations(
+ Flags.trustJSInteropTypeAnnotations)),
new OptionHandler(r'--help|/\?|/h', (_) => wantHelp = true),
new OptionHandler('--packages=.+', setPackageConfig),
new OptionHandler('--package-root=.+|-p.+', setPackageRoot),
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 78c0a37..c24ecbf 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -28,6 +28,7 @@
FunctionElement,
ImportElement,
LibraryElement,
+ LocalFunctionElement,
MetadataAnnotation,
PrefixElement,
ScopeContainerElement,
@@ -48,11 +49,14 @@
NewExpression,
Node;
import 'universe/use.dart' show
+ DynamicUse,
StaticUse,
TypeUse,
TypeUseKind;
import 'universe/world_impact.dart' show
- WorldImpact;
+ ImpactUseCase,
+ WorldImpact,
+ WorldImpactVisitorImpl;
import 'util/setlet.dart' show
Setlet;
import 'util/uri_extras.dart' as uri_extras;
@@ -122,6 +126,8 @@
/// Will be `true` if the program contains deferred libraries.
bool isProgramSplit = false;
+ static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Deferred load');
+
/// A mapping from the name of a defer import to all the output units it
/// depends on in a list of lists to be loaded in the order they appear.
///
@@ -318,30 +324,35 @@
WorldImpact worldImpact =
compiler.resolution.getWorldImpact(analyzableElement);
- worldImpact.staticUses.forEach((StaticUse staticUse) {
- elements.add(staticUse.element);
- });
- for (TypeUse typeUse in worldImpact.typeUses) {
- DartType type = typeUse.type;
- switch (typeUse.kind) {
- case TypeUseKind.TYPE_LITERAL:
- if (type.isTypedef || type.isInterfaceType) {
- elements.add(type.element);
- }
- break;
- case TypeUseKind.INSTANTIATION:
- case TypeUseKind.IS_CHECK:
- case TypeUseKind.AS_CAST:
- case TypeUseKind.CATCH_TYPE:
- collectTypeDependencies(type);
- break;
- case TypeUseKind.CHECKED_MODE_CHECK:
- if (compiler.enableTypeAssertions) {
- collectTypeDependencies(type);
- }
- break;
- }
- }
+ compiler.impactStrategy.visitImpact(
+ analyzableElement,
+ worldImpact,
+ new WorldImpactVisitorImpl(
+ visitStaticUse: (StaticUse staticUse) {
+ elements.add(staticUse.element);
+ },
+ visitTypeUse: (TypeUse typeUse) {
+ DartType type = typeUse.type;
+ switch (typeUse.kind) {
+ case TypeUseKind.TYPE_LITERAL:
+ if (type.isTypedef || type.isInterfaceType) {
+ elements.add(type.element);
+ }
+ break;
+ case TypeUseKind.INSTANTIATION:
+ case TypeUseKind.IS_CHECK:
+ case TypeUseKind.AS_CAST:
+ case TypeUseKind.CATCH_TYPE:
+ collectTypeDependencies(type);
+ break;
+ case TypeUseKind.CHECKED_MODE_CHECK:
+ if (compiler.enableTypeAssertions) {
+ collectTypeDependencies(type);
+ }
+ break;
+ }
+ }),
+ IMPACT_USE);
TreeElements treeElements = analyzableElement.resolvedAst.elements;
assert(treeElements != null);
@@ -711,6 +722,9 @@
// Generate a unique name for each OutputUnit.
_assignNamesToOutputUnits(allOutputUnits);
});
+ // Notify the impact strategy impacts are no longer needed for deferred
+ // load.
+ compiler.impactStrategy.onImpactUsed(IMPACT_USE);
}
void beforeResolution(Compiler compiler) {
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 09ab8e5..207954d 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -4,25 +4,41 @@
library dump_info;
-import 'dart:convert'
- show HtmlEscape, JsonEncoder, StringConversionSink, ChunkedConversionSink;
+import 'dart:convert' show
+ ChunkedConversionSink,
+ HtmlEscape,
+ JsonEncoder,
+ StringConversionSink;
import 'package:dart2js_info/info.dart';
import 'common.dart';
-import 'common/tasks.dart' show CompilerTask;
-import 'constants/values.dart' show ConstantValue, InterceptorConstantValue;
-import 'compiler.dart' show Compiler;
+import 'common/tasks.dart' show
+ CompilerTask;
+import 'constants/values.dart' show
+ ConstantValue,
+ InterceptorConstantValue;
+import 'compiler.dart' show
+ Compiler;
+import 'deferred_load.dart' show
+ OutputUnit;
import 'elements/elements.dart';
import 'elements/visitor.dart';
-import 'types/types.dart' show TypeMask;
-import 'deferred_load.dart' show OutputUnit;
-import 'js_backend/js_backend.dart' show JavaScriptBackend;
-import 'js_emitter/full_emitter/emitter.dart' as full show Emitter;
+import 'info/send_info.dart' show
+ collectSendMeasurements;
+import 'js_backend/js_backend.dart' show
+ JavaScriptBackend;
+import 'js_emitter/full_emitter/emitter.dart' as full show
+ Emitter;
import 'js/js.dart' as jsAst;
-import 'universe/universe.dart' show ReceiverConstraint;
-import 'universe/world_impact.dart' show WorldImpact;
-import 'info/send_info.dart' show collectSendMeasurements;
+import 'types/types.dart' show
+ TypeMask;
+import 'universe/universe.dart' show
+ ReceiverConstraint;
+import 'universe/world_impact.dart' show
+ ImpactUseCase,
+ WorldImpact,
+ WorldImpactVisitorImpl;
class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> {
final Compiler compiler;
@@ -366,6 +382,8 @@
}
class DumpInfoTask extends CompilerTask implements InfoReporter {
+ static const ImpactUseCase IMPACT_USE = const ImpactUseCase('Dump info');
+
DumpInfoTask(Compiler compiler) : super(compiler);
String get name => "Dump Info";
@@ -418,23 +436,34 @@
}
}
+ void unregisterImpact(Element element) {
+ impacts.remove(element);
+ }
+
/**
* Returns an iterable of [Selection]s that are used by
* [element]. Each [Selection] contains an element that is
* used and the selector that selected the element.
*/
Iterable<Selection> getRetaining(Element element) {
- var impact = impacts[element];
+ WorldImpact impact = impacts[element];
if (impact == null) return const <Selection>[];
var selections = <Selection>[];
- selections.addAll(impact.dynamicUses.expand((dynamicUse) {
- return compiler.world.allFunctions
- .filter(dynamicUse.selector, dynamicUse.mask)
- .map((e) => new Selection(e, dynamicUse.mask));
- }));
- selections.addAll(impact.staticUses
- .map((staticUse) => new Selection(staticUse.element, null)));
+ compiler.impactStrategy.visitImpact(
+ element,
+ impact,
+ new WorldImpactVisitorImpl(
+ visitDynamicUse: (dynamicUse) {
+ selections.addAll(compiler.world.allFunctions
+ .filter(dynamicUse.selector, dynamicUse.mask)
+ .map((e) => new Selection(e, dynamicUse.mask)));
+ },
+ visitStaticUse: (staticUse) {
+ selections.add(new Selection(staticUse.element, null));
+ }
+ ),
+ IMPACT_USE);
return selections;
}
@@ -535,6 +564,8 @@
info.uses.add(new DependencyInfo(useInfo, '${selection.mask}'));
}
}
+ // Notify the impact strategy impacts are no longer needed for dump info.
+ compiler.impactStrategy.onImpactUsed(IMPACT_USE);
// Track dependencies that come from inlining.
for (Element element in inlineMap.keys) {
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index 53796dc..2c7403f 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -58,7 +58,9 @@
TypeUse,
TypeUseKind;
import 'universe/world_impact.dart' show
- WorldImpact;
+ ImpactUseCase,
+ WorldImpact,
+ WorldImpactVisitor;
import 'util/util.dart' show
Link,
Setlet;
@@ -117,10 +119,14 @@
bool hasEnqueuedReflectiveElements = false;
bool hasEnqueuedReflectiveStaticFields = false;
+ WorldImpactVisitor impactVisitor;
+
Enqueuer(this.name,
this.compiler,
this.itemCompilationContextCreator,
- this.strategy);
+ this.strategy) {
+ impactVisitor = new _EnqueuerImpactVisitor(this);
+ }
// TODO(johnniwinther): Move this to [ResolutionEnqueuer].
Resolution get resolution => compiler.resolution;
@@ -142,6 +148,8 @@
Iterable<ClassElement> get processedClasses => _processedClasses;
+ ImpactUseCase get impactUse;
+
/**
* Documentation wanted -- johnniwinther
*
@@ -166,10 +174,8 @@
/// Apply the [worldImpact] of processing [element] to this enqueuer.
void applyImpact(Element element, WorldImpact worldImpact) {
- // TODO(johnniwinther): Optimize the application of the world impact.
- worldImpact.dynamicUses.forEach(registerDynamicUse);
- worldImpact.staticUses.forEach(registerStaticUse);
- worldImpact.typeUses.forEach(registerTypeUse);
+ compiler.impactStrategy.visitImpact(
+ element, worldImpact, impactVisitor, impactUse);
}
void registerInstantiatedType(InterfaceType type,
@@ -634,6 +640,7 @@
// enqueue.
addElement = false;
break;
+ case StaticUseKind.SUPER_FIELD_SET:
case StaticUseKind.SUPER_TEAR_OFF:
case StaticUseKind.GENERAL:
break;
@@ -741,6 +748,10 @@
*/
final Queue<DeferredTask> deferredTaskQueue;
+ static const ImpactUseCase IMPACT_USE = const ImpactUseCase('ResolutionEnqueuer');
+
+ ImpactUseCase get impactUse => IMPACT_USE;
+
ResolutionEnqueuer(Compiler compiler,
ItemCompilationContext itemCompilationContextCreator(),
EnqueuerStrategy strategy)
@@ -896,6 +907,10 @@
bool enabledNoSuchMethod = false;
+ static const ImpactUseCase IMPACT_USE = const ImpactUseCase('CodegenEnqueuer');
+
+ ImpactUseCase get impactUse => IMPACT_USE;
+
CodegenEnqueuer(Compiler compiler,
ItemCompilationContext itemCompilationContextCreator(),
EnqueuerStrategy strategy)
@@ -1039,3 +1054,24 @@
enqueuer.handleUnseenSelectorInternal(dynamicUse);
}
}
+
+class _EnqueuerImpactVisitor implements WorldImpactVisitor {
+ final Enqueuer enqueuer;
+
+ _EnqueuerImpactVisitor(this.enqueuer);
+
+ @override
+ void visitDynamicUse(DynamicUse dynamicUse) {
+ enqueuer.registerDynamicUse(dynamicUse);
+ }
+
+ @override
+ void visitStaticUse(StaticUse staticUse) {
+ enqueuer.registerStaticUse(staticUse);
+ }
+
+ @override
+ void visitTypeUse(TypeUse typeUse) {
+ enqueuer.registerTypeUse(typeUse);
+ }
+}
diff --git a/pkg/compiler/lib/src/inferrer/closure_tracer.dart b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
index aa78001..b7d1ef7 100644
--- a/pkg/compiler/lib/src/inferrer/closure_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/closure_tracer.dart
@@ -2,11 +2,20 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of type_graph_inferrer;
+library compiler.src.inferrer.closure_tracer;
+
+import '../types/types.dart' show TypeMask;
+import '../common/names.dart' show Names;
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
+
class ClosureTracerVisitor extends TracerVisitor<ApplyableTypeInformation> {
final Iterable<FunctionElement> tracedElements;
- final List<CallSiteTypeInformation> callsToAnalyze =
+ final List<CallSiteTypeInformation> _callsToAnalyze =
new List<CallSiteTypeInformation>();
ClosureTracerVisitor(this.tracedElements, tracedType, inferrer)
@@ -15,7 +24,7 @@
void run() {
analyze();
if (!continueAnalyzing) return;
- callsToAnalyze.forEach(analyzeCall);
+ _callsToAnalyze.forEach(_analyzeCall);
for(FunctionElement e in tracedElements) {
e.functionSignature.forEachParameter((Element parameter) {
ElementTypeInformation info =
@@ -25,18 +34,18 @@
}
}
- void tagAsFunctionApplyTarget([String reason]) {
+ void _tagAsFunctionApplyTarget([String reason]) {
tracedType.mightBePassedToFunctionApply = true;
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print("Closure $tracedType might be passed to apply: $reason");
}
}
- void registerCallForLaterAnalysis(CallSiteTypeInformation info) {
- callsToAnalyze.add(info);
+ void _registerCallForLaterAnalysis(CallSiteTypeInformation info) {
+ _callsToAnalyze.add(info);
}
- void analyzeCall(CallSiteTypeInformation info) {
+ void _analyzeCall(CallSiteTypeInformation info) {
Selector selector = info.selector;
TypeMask mask = info.mask;
tracedElements.forEach((FunctionElement functionElement) {
@@ -46,15 +55,17 @@
});
}
+ @override
visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
super.visitClosureCallSiteTypeInformation(info);
if (info.closure == currentUser) {
- registerCallForLaterAnalysis(info);
+ _registerCallForLaterAnalysis(info);
} else {
bailout('Passed to a closure');
}
}
+ @override
visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
super.visitStaticCallSiteTypeInformation(info);
Element called = info.calledElement;
@@ -70,23 +81,22 @@
&& inferrer.types.getInferredTypeOf(called) == currentUser) {
// This node can be a closure call as well. For example, `foo()`
// where `foo` is a getter.
- registerCallForLaterAnalysis(info);
+ _registerCallForLaterAnalysis(info);
}
- if (checkIfFunctionApply(called) &&
+ if (_checkIfFunctionApply(called) &&
info.arguments != null &&
info.arguments.contains(currentUser)) {
- tagAsFunctionApplyTarget("static call");
+ _tagAsFunctionApplyTarget("static call");
}
}
- bool checkIfCurrentUser(element) {
- return inferrer.types.getInferredTypeOf(element) == currentUser;
- }
+ bool _checkIfCurrentUser(element) =>
+ inferrer.types.getInferredTypeOf(element) == currentUser;
- bool checkIfFunctionApply(element) {
- return compiler.functionApplyMethod == element;
- }
+ bool _checkIfFunctionApply(element) =>
+ compiler.functionApplyMethod == element;
+ @override
visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
super.visitDynamicCallSiteTypeInformation(info);
if (info.selector.isCall) {
@@ -94,11 +104,11 @@
if (!info.targets.every((element) => element.isFunction)) {
bailout('Passed to a closure');
}
- if (info.targets.any(checkIfFunctionApply)) {
- tagAsFunctionApplyTarget("dynamic call");
+ if (info.targets.any(_checkIfFunctionApply)) {
+ _tagAsFunctionApplyTarget("dynamic call");
}
- } else if (info.targets.any((element) => checkIfCurrentUser(element))) {
- registerCallForLaterAnalysis(info);
+ } else if (info.targets.any((element) => _checkIfCurrentUser(element))) {
+ _registerCallForLaterAnalysis(info);
}
} else if (info.selector.isGetter &&
info.selector.memberName == Names.call) {
@@ -112,6 +122,7 @@
StaticTearOffClosureTracerVisitor(tracedElement, tracedType, inferrer)
: super([tracedElement], tracedType, inferrer);
+ @override
visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
super.visitStaticCallSiteTypeInformation(info);
if (info.calledElement == tracedElements.first
diff --git a/pkg/compiler/lib/src/inferrer/debug.dart b/pkg/compiler/lib/src/inferrer/debug.dart
new file mode 100644
index 0000000..502f966
--- /dev/null
+++ b/pkg/compiler/lib/src/inferrer/debug.dart
@@ -0,0 +1,11 @@
+// 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.
+
+/// Values used only for debugging type inference.
+library compiler.src.inferrer.debug;
+
+bool VERBOSE = false;
+bool PRINT_SUMMARY = false;
+final ANOMALY_WARN = false;
+
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index f9dc9eb..fbb7880 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -91,6 +91,11 @@
T narrowType(T type, DartType annotation, {bool isNullable: true});
/**
+ * Returns the non-nullable type [T].
+ */
+ T narrowNotNull(T type);
+
+ /**
* Returns a new type that unions [firstInput] and [secondInput].
*/
T allocateDiamondPhi(T firstInput, T secondInput);
@@ -469,9 +474,13 @@
SendSet send = node != null ? node.asSendSet() : null;
if (send != null && send.isIfNullAssignment && currentType != null) {
- // If-null assignments may return either the new or the original value.
+ // If-null assignments may return either the new or the original value
+ // narrowed to non-null.
type = types.addPhiInput(
- local, types.allocatePhi(locals.block, local, currentType), type);
+ local,
+ types.allocatePhi(locals.block, local,
+ types.narrowNotNull(currentType)),
+ type);
}
locals[local] = type;
if (currentType != type) {
@@ -1124,7 +1133,7 @@
T visitIfNull(Send node, Node left, Node right, _) {
T firstType = visit(left);
T secondType = visit(right);
- return types.allocateDiamondPhi(firstType, secondType);
+ return types.allocateDiamondPhi(types.narrowNotNull(firstType), secondType);
}
@override
diff --git a/pkg/compiler/lib/src/inferrer/list_tracer.dart b/pkg/compiler/lib/src/inferrer/list_tracer.dart
index b3e8ab3..a57087f 100644
--- a/pkg/compiler/lib/src/inferrer/list_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/list_tracer.dart
@@ -2,7 +2,14 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of type_graph_inferrer;
+library compiler.src.inferrer.list_tracer;
+
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show Setlet;
+
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
/**
* A set of selector names that [List] implements, that we know do not
diff --git a/pkg/compiler/lib/src/inferrer/map_tracer.dart b/pkg/compiler/lib/src/inferrer/map_tracer.dart
index 94caa57..1ab3c24 100644
--- a/pkg/compiler/lib/src/inferrer/map_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/map_tracer.dart
@@ -2,7 +2,13 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of type_graph_inferrer;
+library compiler.src.inferrer.map_tracer;
+
+import '../elements/elements.dart';
+import '../universe/selector.dart' show Selector;
+
+import 'node_tracer.dart';
+import 'type_graph_nodes.dart';
Set<String> okMapSelectorsSet = new Set.from(
const <String>[
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index 371adb5..174ae56 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -2,7 +2,17 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of type_graph_inferrer;
+library compiler.src.inferrer.node_tracer;
+
+import '../common/names.dart' show Identifiers;
+import '../compiler.dart' show Compiler;
+import '../elements/elements.dart';
+import '../types/types.dart' show ContainerTypeMask, MapTypeMask;
+import '../util/util.dart' show Setlet;
+
+import 'type_graph_inferrer.dart' show TypeGraphInferrerEngine;
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
// A set of selectors we know do not escape the elements inside the
// list.
@@ -64,6 +74,7 @@
'keys'
]);
+/// Common logic to trace a value through the type inference graph nodes.
abstract class TracerVisitor<T extends TypeInformation>
implements TypeInformationVisitor {
final T tracedType;
@@ -136,7 +147,7 @@
}
void bailout(String reason) {
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print('Bailing out on $tracedType because: $reason');
}
continueAnalyzing = false;
@@ -202,7 +213,7 @@
flow.users.forEach((user) {
if (user is !DynamicCallSiteTypeInformation) return;
if (user.receiver != flow) return;
- if (inferrer._returnsListElementTypeSet.contains(user.selector)) {
+ if (inferrer.returnsListElementTypeSet.contains(user.selector)) {
addNewEscapeInformation(user);
} else if (!doesNotEscapeListSet.contains(user.selector.name)) {
bailout('Escape from a list via [${user.selector.name}]');
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index 61f8595..f897876 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -52,151 +52,6 @@
import 'inferrer_visitor.dart';
/**
- * An implementation of [TypeSystem] for [TypeMask].
- */
-class TypeMaskSystem implements TypeSystem<TypeMask> {
- final Compiler compiler;
- final ClassWorld classWorld;
- TypeMaskSystem(Compiler compiler)
- : this.compiler = compiler,
- this.classWorld = compiler.world;
-
- TypeMask narrowType(TypeMask type,
- DartType annotation,
- {bool isNullable: true}) {
- if (annotation.treatAsDynamic) return type;
- if (annotation.isObject) return type;
- TypeMask otherType;
- if (annotation.isTypedef || annotation.isFunctionType) {
- otherType = functionType;
- } else if (annotation.isTypeVariable) {
- // TODO(ngeoffray): Narrow to bound.
- return type;
- } else if (annotation.isVoid) {
- otherType = nullType;
- } else {
- assert(annotation.isInterfaceType);
- otherType = new TypeMask.nonNullSubtype(annotation.element, classWorld);
- }
- if (isNullable) otherType = otherType.nullable();
- if (type == null) return otherType;
- return type.intersection(otherType, classWorld);
- }
-
- TypeMask computeLUB(TypeMask firstType, TypeMask secondType) {
- if (firstType == null) {
- return secondType;
- } else if (secondType == dynamicType || firstType == dynamicType) {
- return dynamicType;
- } else if (firstType == secondType) {
- return firstType;
- } else {
- TypeMask union = firstType.union(secondType, classWorld);
- // TODO(kasperl): If the union isn't nullable it seems wasteful
- // to use dynamic. Fix that.
- return union.containsAll(classWorld) ? dynamicType : union;
- }
- }
-
- TypeMask allocateDiamondPhi(TypeMask firstType, TypeMask secondType) {
- return computeLUB(firstType, secondType);
- }
-
- TypeMask get dynamicType => compiler.typesTask.dynamicType;
- TypeMask get nullType => compiler.typesTask.nullType;
- TypeMask get intType => compiler.typesTask.intType;
- TypeMask get uint32Type => compiler.typesTask.uint32Type;
- TypeMask get uint31Type => compiler.typesTask.uint31Type;
- TypeMask get positiveIntType => compiler.typesTask.positiveIntType;
- TypeMask get doubleType => compiler.typesTask.doubleType;
- TypeMask get numType => compiler.typesTask.numType;
- TypeMask get boolType => compiler.typesTask.boolType;
- TypeMask get functionType => compiler.typesTask.functionType;
- TypeMask get listType => compiler.typesTask.listType;
- TypeMask get constListType => compiler.typesTask.constListType;
- TypeMask get fixedListType => compiler.typesTask.fixedListType;
- TypeMask get growableListType => compiler.typesTask.growableListType;
- TypeMask get mapType => compiler.typesTask.mapType;
- TypeMask get constMapType => compiler.typesTask.constMapType;
- TypeMask get stringType => compiler.typesTask.stringType;
- TypeMask get typeType => compiler.typesTask.typeType;
- TypeMask get syncStarIterableType => compiler.typesTask.syncStarIterableType;
- TypeMask get asyncFutureType => compiler.typesTask.asyncFutureType;
- TypeMask get asyncStarStreamType => compiler.typesTask.asyncStarStreamType;
- bool isNull(TypeMask mask) => mask.isEmpty && mask.isNullable;
-
- TypeMask stringLiteralType(ast.DartString value) => stringType;
- TypeMask boolLiteralType(ast.LiteralBool value) => boolType;
-
- TypeMask nonNullSubtype(ClassElement type)
- => new TypeMask.nonNullSubtype(type.declaration, classWorld);
- TypeMask nonNullSubclass(ClassElement type)
- => new TypeMask.nonNullSubclass(type.declaration, classWorld);
- TypeMask nonNullExact(ClassElement type)
- => new TypeMask.nonNullExact(type.declaration, classWorld);
- TypeMask nonNullEmpty() => new TypeMask.nonNullEmpty();
-
- TypeMask allocateList(TypeMask type,
- ast.Node node,
- Element enclosing,
- [TypeMask elementType, int length]) {
- return new ContainerTypeMask(type, node, enclosing, elementType, length);
- }
-
- TypeMask allocateMap(TypeMask type, ast.Node node, Element element,
- [List<TypeMask> keys, List<TypeMask> values]) {
- return type;
- }
-
- TypeMask allocateClosure(ast.Node node, Element element) {
- return functionType;
- }
-
- TypeMask newTypedSelector(TypeMask receiver, TypeMask mask) {
- return receiver;
- }
-
- TypeMask addPhiInput(Local variable,
- TypeMask phiType,
- TypeMask newType) {
- return computeLUB(phiType, newType);
- }
-
- TypeMask allocatePhi(ast.Node node,
- Local variable,
- TypeMask inputType) {
- return inputType;
- }
-
- TypeMask allocateLoopPhi(ast.Node node,
- Local variable,
- TypeMask inputType) {
- return inputType;
- }
-
- TypeMask simplifyPhi(ast.Node node,
- Local variable,
- TypeMask phiType) {
- return phiType;
- }
-
- bool selectorNeedsUpdate(TypeMask type, TypeMask mask) {
- return type != mask;
- }
-
- TypeMask refineReceiver(Selector selector,
- TypeMask mask,
- TypeMask receiverType,
- bool isConditional) {
- TypeMask newType =
- compiler.world.allFunctions.receiverType(selector, mask);
- return receiverType.intersection(newType, classWorld);
- }
-
- TypeMask getConcreteTypeFor(TypeMask mask) => mask;
-}
-
-/**
* Common super class used by [SimpleTypeInferrerVisitor] to propagate
* type information about visited nodes, as well as to request type
* information of elements.
@@ -482,6 +337,15 @@
}
}
+/// [SimpleTypeInferrerVisitor] can be thought of as a type-inference graph
+/// builder for a single element.
+///
+/// Calling [run] will start the work of visiting the body of the code to
+/// construct a set of infernece-nodes that abstractly represent what the code
+/// is doing.
+///
+/// This visitor is parameterized by an [InferenceEngine], which internally
+/// decides how to represent inference nodes.
class SimpleTypeInferrerVisitor<T>
extends InferrerVisitor<T, InferrerEngine<T, TypeSystem<T>>> {
T returnType;
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index 4a03baf..a568066 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -4,9 +4,7 @@
library type_graph_inferrer;
-import 'dart:collection' show
- IterableBase,
- Queue;
+import 'dart:collection' show Queue;
import '../common.dart';
import '../common/names.dart' show
@@ -15,8 +13,6 @@
import '../compiler.dart' show
Compiler;
import '../constants/values.dart';
-import '../cps_ir/cps_ir_nodes.dart' as cps_ir show
- Node;
import '../dart_types.dart' show
DartType,
FunctionType,
@@ -26,7 +22,6 @@
import '../js_backend/js_backend.dart' show
Annotations,
JavaScriptBackend;
-import '../native/native.dart' as native;
import '../resolution/tree_elements.dart' show
TreeElementMapping;
import '../tree/tree.dart' as ast show
@@ -38,11 +33,9 @@
TryStatement;
import '../types/types.dart' show
ContainerTypeMask,
- DictionaryTypeMask,
MapTypeMask,
TypeMask,
- TypesInferrer,
- ValueTypeMask;
+ TypesInferrer;
import '../types/constants.dart' show
computeTypeMask;
import '../universe/call_structure.dart' show
@@ -62,15 +55,12 @@
TypeSystem;
import 'simple_types_inferrer.dart';
-part 'closure_tracer.dart';
-part 'list_tracer.dart';
-part 'map_tracer.dart';
-part 'node_tracer.dart';
-part 'type_graph_nodes.dart';
+import 'closure_tracer.dart';
+import 'list_tracer.dart';
+import 'map_tracer.dart';
+import 'type_graph_nodes.dart';
+import 'debug.dart' as debug;
-bool _VERBOSE = false;
-bool _PRINT_SUMMARY = false;
-final _ANOMALY_WARN = false;
class TypeInformationSystem extends TypeSystem<TypeInformation> {
final Compiler compiler;
@@ -337,6 +327,16 @@
}
}
+ TypeInformation narrowNotNull(TypeInformation type) {
+ if (type.type.isExact && !type.type.isNullable) {
+ return type;
+ }
+ TypeInformation newType =
+ new NarrowTypeInformation(type, dynamicType.type.nonNullable());
+ allocatedTypes.add(newType);
+ return newType;
+ }
+
ElementTypeInformation getInferredTypeOf(Element element) {
element = element.implementation;
return typeInformations.putIfAbsent(element, () {
@@ -612,7 +612,7 @@
* A set of selector names that [List] implements, that we know return
* their element type.
*/
- final Set<Selector> _returnsListElementTypeSet = new Set<Selector>.from(
+ final Set<Selector> returnsListElementTypeSet = new Set<Selector>.from(
<Selector>[
new Selector.getter(const PublicName('first')),
new Selector.getter(const PublicName('last')),
@@ -627,7 +627,7 @@
bool returnsListElementType(Selector selector, TypeMask mask) {
return mask != null &&
mask.isContainer &&
- _returnsListElementTypeSet.contains(selector);
+ returnsListElementTypeSet.contains(selector);
}
bool returnsMapValueType(Selector selector, TypeMask mask) {
@@ -723,7 +723,7 @@
if (!tracer.continueAnalyzing) {
elements.forEach((FunctionElement e) {
compiler.world.registerMightBePassedToApply(e);
- if (_VERBOSE) print("traced closure $e as ${true} (bail)");
+ if (debug.VERBOSE) print("traced closure $e as ${true} (bail)");
e.functionSignature.forEachParameter((parameter) {
types.getInferredTypeOf(parameter).giveUp(
this,
@@ -744,7 +744,7 @@
if (tracer.tracedType.mightBePassedToFunctionApply) {
compiler.world.registerMightBePassedToApply(e);
};
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print("traced closure $e as "
"${compiler.world.getMightBePassedToApply(e)}");
}
@@ -798,7 +798,7 @@
workQueue.addAll(seenTypes);
refine();
- if (_PRINT_SUMMARY) {
+ if (debug.PRINT_SUMMARY) {
types.allocatedLists.values.forEach((ListTypeInformation info) {
print('${info.type} '
'for ${info.originalType.allocationNode} '
@@ -946,7 +946,7 @@
overallRefineCount++;
info.refineCount++;
if (info.refineCount > MAX_CHANGE_COUNT) {
- if (_ANOMALY_WARN) {
+ if (debug.ANOMALY_WARN) {
print("ANOMALY WARNING: max refinement reached for $info");
}
info.giveUp(this);
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index dd506519..cbc662c 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -2,7 +2,44 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of type_graph_inferrer;
+library compiler.src.inferrer.type_graph_nodes;
+
+import 'dart:collection' show IterableBase;
+
+import '../common.dart';
+import '../common/names.dart' show Identifiers;
+import '../compiler.dart' show Compiler;
+import '../constants/values.dart';
+import '../cps_ir/cps_ir_nodes.dart' as cps_ir show Node;
+import '../dart_types.dart' show
+ DartType,
+ FunctionType,
+ InterfaceType,
+ TypeKind;
+import '../elements/elements.dart';
+import '../native/native.dart' as native;
+import '../tree/tree.dart' as ast show
+ DartString,
+ Node,
+ LiteralBool,
+ Send,
+ SendSet,
+ TryStatement;
+import '../types/types.dart' show
+ ContainerTypeMask,
+ DictionaryTypeMask,
+ MapTypeMask,
+ TypeMask,
+ ValueTypeMask;
+import '../universe/selector.dart' show Selector;
+import '../util/util.dart' show ImmutableEmptySet, Setlet;
+import '../world.dart' show ClassWorld;
+
+import 'inferrer_visitor.dart' show ArgumentsTypes;
+import 'type_graph_inferrer.dart' show
+ TypeGraphInferrerEngine,
+ TypeInformationSystem;
+import 'debug.dart' as debug;
/**
* Common class for all nodes in the graph. The current nodes are:
@@ -455,14 +492,14 @@
return mask;
}
if (element.isField) {
- return new TypeMaskSystem(compiler).narrowType(mask, element.type);
+ return _narrowType(compiler, mask, element.type);
}
assert(element.isFunction ||
element.isGetter ||
element.isFactoryConstructor);
FunctionType type = element.type;
- return new TypeMaskSystem(compiler).narrowType(mask, type.returnType);
+ return _narrowType(compiler, mask, type.returnType);
}
TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@@ -594,7 +631,7 @@
// ignore type annotations to ensure that the checks are actually inserted
// into the function body and retained until runtime.
assert(!compiler.enableTypeAssertions);
- return new TypeMaskSystem(compiler).narrowType(mask, element.type);
+ return _narrowType(compiler, mask, element.type);
}
TypeMask computeType(TypeGraphInferrerEngine inferrer) {
@@ -935,7 +972,7 @@
ValueTypeMask arg = arguments.positional[0].type;
String key = arg.value.primitiveValue.slowToString();
if (dictionaryTypeMask.typeMap.containsKey(key)) {
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print("Dictionary lookup for $key yields "
"${dictionaryTypeMask.typeMap[key]}.");
}
@@ -943,14 +980,14 @@
} else {
// The typeMap is precise, so if we do not find the key, the lookup
// will be [null] at runtime.
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print("Dictionary lookup for $key yields [null].");
}
return inferrer.types.nullType.type;
}
}
MapTypeMask mapTypeMask = typeMask;
- if (_VERBOSE) {
+ if (debug.VERBOSE) {
print(
"Map lookup for $selector yields ${mapTypeMask.valueType}.");
}
@@ -1180,7 +1217,7 @@
TypeMask input = assignments.first.type;
TypeMask intersection = input.intersection(typeAnnotation,
inferrer.classWorld);
- if (_ANOMALY_WARN) {
+ if (debug.ANOMALY_WARN) {
if (!input.containsMask(intersection, inferrer.classWorld) ||
!typeAnnotation.containsMask(intersection, inferrer.classWorld)) {
print("ANOMALY WARNING: narrowed $input to $intersection via "
@@ -1611,3 +1648,24 @@
T visitClosureTypeInformation(ClosureTypeInformation info);
T visitAwaitTypeInformation(AwaitTypeInformation info);
}
+
+TypeMask _narrowType(Compiler compiler, TypeMask type, DartType annotation,
+ {bool isNullable: true}) {
+ if (annotation.treatAsDynamic) return type;
+ if (annotation.isObject) return type;
+ TypeMask otherType;
+ if (annotation.isTypedef || annotation.isFunctionType) {
+ otherType = compiler.typesTask.functionType;
+ } else if (annotation.isTypeVariable) {
+ // TODO(ngeoffray): Narrow to bound.
+ return type;
+ } else if (annotation.isVoid) {
+ otherType = compiler.typesTask.nullType;
+ } else {
+ assert(annotation.isInterfaceType);
+ otherType = new TypeMask.nonNullSubtype(annotation.element, compiler.world);
+ }
+ if (isNullable) otherType = otherType.nullable();
+ if (type == null) return otherType;
+ return type.intersection(otherType, compiler.world);
+}
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0fed323..5bd42a1 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -581,6 +581,52 @@
new Namer(compiler);
}
+ /// The backend must *always* call this method when enqueuing an
+ /// element. Calls done by the backend are not seen by global
+ /// optimizations, so they would make these optimizations unsound.
+ /// Therefore we need to collect the list of helpers the backend may
+ /// use.
+ // TODO(johnniwinther): Replace this with a more precise modelling; type
+ // inference of these elements is disabled.
+ Element registerBackendUse(Element element) {
+ if (element != null) {
+ bool registerUse = false;
+ if (element == helpers.streamIteratorConstructor ||
+ element == helpers.compiler.symbolConstructor ||
+ element == helpers.compiler.symbolValidatedConstructor ||
+ element == helpers.syncCompleterConstructor ||
+ element == coreClasses.symbolClass ||
+ element == helpers.objectNoSuchMethod) {
+ // TODO(johnniwinther): These are valid but we could be more precise.
+ registerUse = true;
+ } else if (element.implementationLibrary.isPatch ||
+ element.library == helpers.jsHelperLibrary ||
+ element.library == helpers.interceptorsLibrary ||
+ element.library == helpers.isolateHelperLibrary) {
+ // TODO(johnniwinther): We should be more precise about these.
+ registerUse = true;
+ } else if (element == coreClasses.listClass ||
+ element == helpers.mapLiteralClass ||
+ element == coreClasses.functionClass ||
+ element == coreClasses.stringClass) {
+ // TODO(johnniwinther): Avoid these.
+ registerUse = true;
+ }
+ if (!registerUse) {
+ assert(invariant(element, false,
+ message: "Backend use of $element is not allowed."));
+ return element;
+ }
+ helpersUsed.add(element.declaration);
+ if (element.isClass && element.isPatched) {
+ // Both declaration and implementation may declare fields, so we
+ // add both to the list of helpers.
+ helpersUsed.add(element.implementation);
+ }
+ }
+ return element;
+ }
+
bool usedByBackend(Element element) {
if (element.isParameter
|| element.isInitializingFormal
@@ -1479,23 +1525,6 @@
compiler.enabledRuntimeType;
}
- /// The backend must *always* call this method when enqueuing an
- /// element. Calls done by the backend are not seen by global
- /// optimizations, so they would make these optimizations unsound.
- /// Therefore we need to collect the list of helpers the backend may
- /// use.
- Element registerBackendUse(Element element) {
- if (element != null) {
- helpersUsed.add(element.declaration);
- if (element.isClass && element.isPatched) {
- // Both declaration and implementation may declare fields, so we
- // add both to the list of helpers.
- helpersUsed.add(element.implementation);
- }
- }
- return element;
- }
-
/// Enqueue [e] in [enqueuer].
///
/// This method calls [registerBackendUse].
@@ -1602,7 +1631,10 @@
}
generatedCode[element] = functionCompiler.compile(work);
- return impactTransformer.transformCodegenImpact(work.registry.worldImpact);
+ WorldImpact worldImpact =
+ impactTransformer.transformCodegenImpact(work.registry.worldImpact);
+ compiler.dumpInfoTask.registerImpact(element, worldImpact);
+ return worldImpact;
}
native.NativeEnqueuer nativeResolutionEnqueuer(Enqueuer world) {
@@ -2611,6 +2643,17 @@
if (patchLocation == null) return null;
return platformConfigUri.resolve(patchLocation);
}
+
+ @override
+ ImpactStrategy createImpactStrategy(
+ {bool supportDeferredLoad: true,
+ bool supportDumpInfo: true}) {
+ return new JavaScriptImpactStrategy(
+ resolution,
+ compiler.dumpInfoTask,
+ supportDeferredLoad: supportDeferredLoad,
+ supportDumpInfo: supportDumpInfo);
+ }
}
/// Handling of special annotations for tests.
@@ -3079,3 +3122,46 @@
const Dependency(this.constant, this.annotatedElement);
}
+
+class JavaScriptImpactStrategy extends ImpactStrategy {
+ final Resolution resolution;
+ final DumpInfoTask dumpInfoTask;
+ final bool supportDeferredLoad;
+ final bool supportDumpInfo;
+
+ JavaScriptImpactStrategy(this.resolution,
+ this.dumpInfoTask,
+ {this.supportDeferredLoad,
+ this.supportDumpInfo});
+
+ @override
+ void visitImpact(Element element,
+ WorldImpact impact,
+ WorldImpactVisitor visitor,
+ ImpactUseCase impactUse) {
+ // TODO(johnniwinther): Compute the application strategy once for each use.
+ if (impactUse == ResolutionEnqueuer.IMPACT_USE) {
+ if (supportDeferredLoad) {
+ impact.apply(visitor);
+ } else {
+ impact.apply(visitor);
+ resolution.uncacheWorldImpact(element);
+ }
+ } else if (impactUse == DeferredLoadTask.IMPACT_USE) {
+ impact.apply(visitor);
+ // Impacts are uncached globally in [onImpactUsed].
+ } else if (impactUse == DumpInfoTask.IMPACT_USE) {
+ impact.apply(visitor);
+ dumpInfoTask.unregisterImpact(element);
+ } else {
+ impact.apply(visitor);
+ }
+ }
+
+ @override
+ void onImpactUsed(ImpactUseCase impactUse) {
+ if (impactUse == DeferredLoadTask.IMPACT_USE) {
+ resolution.emptyCache();
+ }
+ }
+}
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
index d0b2750..f0a92d7 100644
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart
@@ -6,6 +6,7 @@
import '../common.dart';
import '../common/names.dart' show
+ Identifiers,
Uris;
import '../common/resolution.dart' show
Resolution;
@@ -679,4 +680,18 @@
Element get convertRtiToRuntimeType {
return findHelper('convertRtiToRuntimeType');
}
+
+ ClassElement get stackTraceClass {
+ return findHelper('_StackTrace');
+ }
+
+ MethodElement _objectNoSuchMethod;
+
+ MethodElement get objectNoSuchMethod {
+ if (_objectNoSuchMethod == null) {
+ _objectNoSuchMethod =
+ coreClasses.objectClass.lookupLocalMember(Identifiers.noSuchMethod_);
+ }
+ return _objectNoSuchMethod;
+ }
}
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 3320c2f..f25e13b 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -68,8 +68,8 @@
helpers.getRuntimeTypeInfo,
helpers.computeSignature,
helpers.getRuntimeTypeArguments],
- instantiatedClasses: [
- coreClasses.listClass]);
+ otherImpacts: [
+ listValues]);
}
return _computeSignature;
}
@@ -187,6 +187,74 @@
return _throwNoSuchMethod;
}
+ BackendImpact _stringValues;
+
+ BackendImpact get stringValues {
+ if (_stringValues == null) {
+ _stringValues = new BackendImpact(
+ instantiatedClasses: [
+ helpers.jsStringClass]);
+ }
+ return _stringValues;
+ }
+
+ BackendImpact _numValues;
+
+ BackendImpact get numValues {
+ if (_numValues == null) {
+ _numValues = new BackendImpact(
+ instantiatedClasses: [
+ helpers.jsIntClass,
+ helpers.jsPositiveIntClass,
+ helpers.jsUInt32Class,
+ helpers.jsUInt31Class,
+ helpers.jsNumberClass,
+ helpers.jsDoubleClass]);
+ }
+ return _numValues;
+ }
+
+ BackendImpact get intValues => numValues;
+
+ BackendImpact get doubleValues => numValues;
+
+ BackendImpact _boolValues;
+
+ BackendImpact get boolValues {
+ if (_boolValues == null) {
+ _boolValues = new BackendImpact(
+ instantiatedClasses: [
+ helpers.jsBoolClass]);
+ }
+ return _boolValues;
+ }
+
+ BackendImpact _nullValue;
+
+ BackendImpact get nullValue {
+ if (_nullValue == null) {
+ _nullValue = new BackendImpact(
+ instantiatedClasses: [
+ helpers.jsNullClass]);
+ }
+ return _nullValue;
+ }
+
+ BackendImpact _listValues;
+
+ BackendImpact get listValues {
+ if (_listValues == null) {
+ _listValues = new BackendImpact(
+ instantiatedClasses: [
+ helpers.jsArrayClass,
+ helpers.jsMutableArrayClass,
+ helpers.jsFixedArrayClass,
+ helpers.jsExtendableArrayClass,
+ helpers.jsUnmodifiableArrayClass]);
+ }
+ return _listValues;
+ }
+
BackendImpact _throwRuntimeError;
BackendImpact get throwRuntimeError {
@@ -194,9 +262,9 @@
_throwRuntimeError = new BackendImpact(
staticUses: [
helpers.throwRuntimeError],
- // Also register the types of the arguments passed to this method.
- instantiatedClasses: [
- coreClasses.stringClass]);
+ otherImpacts: [
+ // Also register the types of the arguments passed to this method.
+ stringValues]);
}
return _throwRuntimeError;
}
@@ -208,8 +276,7 @@
_superNoSuchMethod = new BackendImpact(
staticUses: [
helpers.createInvocationMirror,
- coreClasses.objectClass.lookupLocalMember(
- Identifiers.noSuchMethod_)],
+ helpers.objectNoSuchMethod],
otherImpacts: [
_needsInt(
'Needed to encode the invocation kind of super.noSuchMethod.'),
@@ -277,23 +344,19 @@
/// Helper for registering that `int` is needed.
BackendImpact _needsInt(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
- return new BackendImpact(
- instantiatedClasses: [coreClasses.intClass]);
+ return intValues;
}
/// Helper for registering that `List` is needed.
BackendImpact _needsList(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
- return new BackendImpact(
- instantiatedClasses: [coreClasses.listClass]);
+ return listValues;
}
/// Helper for registering that `String` is needed.
BackendImpact _needsString(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.
- return new BackendImpact(
- instantiatedClasses: [
- coreClasses.stringClass]);
+ return stringValues;
}
BackendImpact _assertWithoutMessage;
@@ -352,62 +415,15 @@
return _stringJuxtaposition;
}
- // TODO(johnniwinther): Point to to the JavaScript classes instead of the Dart
- // classes in these impacts.
- BackendImpact _nullLiteral;
+ BackendImpact get nullLiteral => nullValue;
- BackendImpact get nullLiteral {
- if (_nullLiteral == null) {
- _nullLiteral = new BackendImpact(
- instantiatedClasses: [
- coreClasses.nullClass]);
- }
- return _nullLiteral;
- }
+ BackendImpact get boolLiteral => boolValues;
- BackendImpact _boolLiteral;
+ BackendImpact get intLiteral => intValues;
- BackendImpact get boolLiteral {
- if (_boolLiteral == null) {
- _boolLiteral = new BackendImpact(
- instantiatedClasses: [
- coreClasses.boolClass]);
- }
- return _boolLiteral;
- }
+ BackendImpact get doubleLiteral => doubleValues;
- BackendImpact _intLiteral;
-
- BackendImpact get intLiteral {
- if (_intLiteral == null) {
- _intLiteral = new BackendImpact(
- instantiatedClasses: [
- coreClasses.intClass]);
- }
- return _intLiteral;
- }
-
- BackendImpact _doubleLiteral;
-
- BackendImpact get doubleLiteral {
- if (_doubleLiteral == null) {
- _doubleLiteral = new BackendImpact(
- instantiatedClasses: [
- coreClasses.doubleClass]);
- }
- return _doubleLiteral;
- }
-
- BackendImpact _stringLiteral;
-
- BackendImpact get stringLiteral {
- if (_stringLiteral == null) {
- _stringLiteral = new BackendImpact(
- instantiatedClasses: [
- coreClasses.stringClass]);
- }
- return _stringLiteral;
- }
+ BackendImpact get stringLiteral => stringValues;
BackendImpact _catchStatement;
@@ -468,7 +484,7 @@
if (_stackTraceInCatch == null) {
_stackTraceInCatch = new BackendImpact(
instantiatedClasses: [
- coreClasses.stackTraceClass],
+ helpers.stackTraceClass],
staticUses: [
helpers.traceFromException]);
}
@@ -498,9 +514,8 @@
helpers.getRuntimeTypeInfo,
helpers.runtimeTypeToString,
helpers.createRuntimeType],
- instantiatedClasses: [
- coreClasses.listClass],
otherImpacts: [
+ listValues,
getRuntimeTypeArgument,
_needsInt('Needed for accessing a type variable literal on this.')
]);
@@ -513,8 +528,8 @@
BackendImpact get typeCheck {
if (_typeCheck == null) {
_typeCheck = new BackendImpact(
- instantiatedClasses: [
- coreClasses.boolClass]);
+ otherImpacts: [
+ boolValues]);
}
return _typeCheck;
}
@@ -551,9 +566,8 @@
// TODO(johnniwinther): Investigate why this is needed.
helpers.setRuntimeTypeInfo,
helpers.getRuntimeTypeInfo],
- instantiatedClasses: [
- coreClasses.listClass],
otherImpacts: [
+ listValues,
getRuntimeTypeArgument]);
}
return _genericTypeCheck;
@@ -564,8 +578,8 @@
BackendImpact get genericIsCheck {
if (_genericIsCheck == null) {
_genericIsCheck = new BackendImpact(
- instantiatedClasses: [
- coreClasses.listClass]);
+ otherImpacts: [
+ intValues]);
}
return _genericIsCheck;
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index bcf0968..8bb26fd 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -68,6 +68,18 @@
final tree_ir.FallthroughStack shortContinue =
new tree_ir.FallthroughStack();
+ /// When the top element is true, [Unreachable] statements will be emitted
+ /// as [Return]s, otherwise they are emitted as empty because they are
+ /// followed by the end of the method.
+ ///
+ /// Note on why the [fallthrough] stack should not be used for this:
+ /// Ordinary statements may choose whether to use the [fallthrough] target,
+ /// and the choice to do so may disable an optimization in [visitIf].
+ /// But omitting an unreachable 'return' should have lower priority than
+ /// the optimizations in [visitIf], so [visitIf] will instead tell the
+ /// [Unreachable] statements whether they may use fallthrough or not.
+ List<bool> emitUnreachableAsReturn = <bool>[false];
+
Set<tree_ir.Label> usedLabels = new Set<tree_ir.Label>();
List<js.Statement> accumulator = new List<js.Statement>();
@@ -272,6 +284,7 @@
void registerMethodInvoke(tree_ir.InvokeMethod node) {
Selector selector = node.selector;
TypeMask mask = node.mask;
+ mask = glue.extendMaskIfReachesAll(selector, mask);
if (selector.isGetter) {
registry.registerDynamicUse(new DynamicUse(selector, mask));
} else if (selector.isSetter) {
@@ -533,16 +546,34 @@
@override
void visitExpressionStatement(tree_ir.ExpressionStatement node) {
- accumulator.add(new js.ExpressionStatement(
- visitExpression(node.expression)));
- visitStatement(node.next);
+ js.Expression exp = visitExpression(node.expression);
+ if (node.next is tree_ir.Unreachable && emitUnreachableAsReturn.last) {
+ // Emit as 'return exp' to assist local analysis in the VM.
+ accumulator.add(new js.Return(exp));
+ } else {
+ accumulator.add(new js.ExpressionStatement(exp));
+ visitStatement(node.next);
+ }
+ }
+
+ bool isNullReturn(tree_ir.Statement node) {
+ return node is tree_ir.Return && isNull(node.value);
+ }
+
+ bool isEndOfMethod(tree_ir.Statement node) {
+ return isNullReturn(node) ||
+ node is tree_ir.Break && isNullReturn(node.target.binding.next);
}
@override
void visitIf(tree_ir.If node) {
js.Expression condition = visitExpression(node.condition);
int usesBefore = fallthrough.useCount;
+ // Unless the 'else' part ends the method. make sure to terminate any
+ // uncompletable code paths in the 'then' part.
+ emitUnreachableAsReturn.add(!isEndOfMethod(node.elseStatement));
js.Statement thenBody = buildBodyStatement(node.thenStatement);
+ emitUnreachableAsReturn.removeLast();
bool thenHasFallthrough = (fallthrough.useCount > usesBefore);
if (thenHasFallthrough) {
js.Statement elseBody = buildBodyStatement(node.elseStatement);
@@ -613,7 +644,9 @@
shortBreak.push(node.next);
shortContinue.push(node);
fallthrough.push(node);
+ emitUnreachableAsReturn.add(true);
js.Statement body = buildBodyStatement(node.body);
+ emitUnreachableAsReturn.removeLast();
fallthrough.pop();
shortContinue.pop();
shortBreak.pop();
@@ -643,7 +676,9 @@
shortBreak.push(fallthrough.target);
shortContinue.push(node);
fallthrough.push(node);
+ emitUnreachableAsReturn.add(true);
js.Statement jsBody = buildBodyStatement(node.body);
+ emitUnreachableAsReturn.removeLast();
fallthrough.pop();
shortContinue.pop();
if (shortBreak.useCount > 0) {
@@ -682,8 +717,10 @@
@override
void visitUnreachable(tree_ir.Unreachable node) {
- // Output nothing.
- // TODO(asgerf): Emit a throw/return to assist local analysis in the VM?
+ if (emitUnreachableAsReturn.last) {
+ // Emit a return to assist local analysis in the VM.
+ accumulator.add(new js.Return());
+ }
}
@override
@@ -949,6 +986,8 @@
case BuiltinOperator.StringConcatenate:
if (args.isEmpty) return js.string('');
return args.reduce((e1,e2) => new js.Binary('+', e1, e2));
+ case BuiltinOperator.CharCodeAt:
+ return js.js('#.charCodeAt(#)', args);
case BuiltinOperator.Identical:
registry.registerStaticUse(new StaticUse.staticInvoke(
glue.identicalFunction, new CallStructure.unnamed(args.length)));
@@ -1072,12 +1111,6 @@
return new js.Await(visitExpression(node.input));
}
- visitFunctionExpression(tree_ir.FunctionExpression node) {
- // FunctionExpressions are currently unused.
- // We might need them if we want to emit raw JS nested functions.
- throw 'FunctionExpressions should not be used';
- }
-
/// Ensures that parameter defaults will be emitted.
///
/// Ideally, this should be done when generating the relevant stub methods,
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index b441960..463d6da 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -30,7 +30,7 @@
Selector;
import '../../world.dart' show
ClassWorld;
-
+import '../../types/types.dart';
/// Encapsulates the dependencies of the function-compiler to the compiler,
/// backend and emitter.
@@ -287,5 +287,9 @@
return _backend.constants.getConstantValueForVariable(elem);
}
+ TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) {
+ return _compiler.world.extendMaskIfReachesAll(selector, mask);
+ }
+
FunctionElement get closureFromTearOff => _backend.helpers.closureFromTearOff;
}
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index d9881b2..cad67af 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -201,13 +201,14 @@
cps.FunctionDefinition optimizeCpsIr(cps.FunctionDefinition cpsFunction) {
cpsOptimizationTask.measure(() {
- TypeMaskSystem typeSystem = new TypeMaskSystem(compiler);
-
applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
applyCpsPass(new InsertRefinements(typeSystem), cpsFunction);
applyCpsPass(new TypePropagator(compiler, typeSystem, this), cpsFunction);
- applyCpsPass(new ShareFinalFields(backend), cpsFunction);
+ applyCpsPass(new RedundantJoinEliminator(), cpsFunction);
+ applyCpsPass(new ShrinkingReducer(), cpsFunction);
+ applyCpsPass(new RedundantRefinementEliminator(typeSystem), cpsFunction);
+ applyCpsPass(new GVN(compiler), cpsFunction);
applyCpsPass(new RemoveRefinements(), cpsFunction);
applyCpsPass(new ShrinkingReducer(), cpsFunction);
applyCpsPass(new ScalarReplacer(compiler), cpsFunction);
@@ -216,7 +217,7 @@
applyCpsPass(new RedundantPhiEliminator(), cpsFunction);
applyCpsPass(new BoundsChecker(typeSystem, compiler.world), cpsFunction);
applyCpsPass(new ShrinkingReducer(), cpsFunction);
- applyCpsPass(new ShareInterceptors(backend), cpsFunction);
+ applyCpsPass(new OptimizeInterceptors(backend), cpsFunction);
applyCpsPass(new ShrinkingReducer(), cpsFunction);
});
return cpsFunction;
diff --git a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
index 3fa6f18..f1f5dd0 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/unsugar.dart
@@ -9,6 +9,7 @@
import '../../universe/selector.dart' show Selector;
import '../../cps_ir/cps_ir_builder.dart' show ThisParameterLocal;
import '../../cps_ir/cps_fragment.dart';
+import '../../common/names.dart';
class ExplicitReceiverParameterEntity implements Local {
String get name => 'receiver';
@@ -77,7 +78,7 @@
}
if (inInterceptedMethod && methodUsesReceiverArgument(function.element)) {
- explicitReceiverParameter.substituteFor(thisParameter);
+ thisParameter.replaceUsesWith(explicitReceiverParameter);
}
visit(function);
@@ -95,11 +96,6 @@
return new Constant(new NullConstantValue());
}
- void insertLetPrim(Primitive primitive, Expression node) {
- LetPrim let = new LetPrim(primitive);
- let.insertAbove(node);
- }
-
void insertEqNullCheck(FunctionDefinition function) {
// Replace
//
@@ -122,30 +118,15 @@
cps.insertAbove(function.body);
}
- /// Insert a static call to [function] at the point of [node] with result
- /// [result].
- ///
- /// Rewrite [node] to
- ///
- /// let cont continuation(result) = node
- /// in invoke function arguments continuation
- void insertStaticCall(FunctionElement function, List<Primitive> arguments,
- Parameter result, Expression node) {
- InteriorNode parent = node.parent;
- Continuation continuation = new Continuation([result]);
-
- Selector selector = new Selector.fromElement(function);
+ /// Insert a static call to [function] immediately above [node].
+ Primitive insertStaticCallAbove(FunctionElement function,
+ List<Primitive> arguments, Expression node) {
// TODO(johnniwinther): Come up with an implementation of SourceInformation
// for calls such as this one that don't appear in the original source.
InvokeStatic invoke = new InvokeStatic(
- function, selector, arguments, continuation, null);
-
- LetCont letCont = new LetCont(continuation, invoke);
-
- parent.body = letCont;
- letCont.parent = parent;
- continuation.body = node;
- node.parent = continuation;
+ function, new Selector.fromElement(function), arguments, null);
+ new LetPrim(invoke).insertAbove(node);
+ return invoke;
}
@override
@@ -161,16 +142,22 @@
Expression body = node.handler.body;
if (_exceptionParameter.hasAtLeastOneUse ||
stackTraceParameter.hasAtLeastOneUse) {
- Parameter exceptionValue = new Parameter(null);
- exceptionValue.substituteFor(_exceptionParameter);
- insertStaticCall(_glue.getExceptionUnwrapper(), [_exceptionParameter],
- exceptionValue, body);
+ InvokeStatic unwrapped = insertStaticCallAbove(
+ _glue.getExceptionUnwrapper(),
+ [new Parameter(null)], // Dummy argument, see below.
+ body);
+ _exceptionParameter.replaceUsesWith(unwrapped);
+
+ // Replace the dummy with the exception parameter. It must be set after
+ // replacing all uses of [_exceptionParameter].
+ unwrapped.arguments[0].changeTo(_exceptionParameter);
if (stackTraceParameter.hasAtLeastOneUse) {
- Parameter stackTraceValue = new Parameter(null);
- stackTraceValue.substituteFor(stackTraceParameter);
- insertStaticCall(_glue.getTraceFromException(), [_exceptionParameter],
- stackTraceValue, body);
+ InvokeStatic stackTraceValue = insertStaticCallAbove(
+ _glue.getTraceFromException(),
+ [_exceptionParameter],
+ body);
+ stackTraceParameter.replaceUsesWith(stackTraceValue);
}
}
@@ -185,9 +172,10 @@
processThrow(Throw node) {
// The subexpression of throw is wrapped in the JavaScript output.
- Parameter wrappedException = new Parameter(null);
- insertStaticCall(_glue.getWrapExceptionHelper(), [node.value.definition],
- wrappedException, node);
+ Primitive wrappedException = insertStaticCallAbove(
+ _glue.getWrapExceptionHelper(),
+ [node.value.definition],
+ node);
node.value.changeTo(wrappedException);
}
@@ -202,22 +190,26 @@
// worry about unlinking.
}
- // TODO(24523): Insert interceptor on demand when we discover we want to use
- // one rather than on every check.
- processTypeTest(TypeTest node) {
- assert(node.interceptor == null);
- Primitive receiver = node.value.definition;
- Primitive interceptor = new Interceptor(receiver, node.sourceInformation)
- ..interceptedClasses.addAll(_glue.interceptedClasses);
- insertLetPrim(interceptor, node.parent);
- node.interceptor = new Reference<Primitive>(interceptor);
- node.interceptor.parent = node;
+ bool isNullConstant(Primitive prim) {
+ return prim is Constant && prim.value.isNull;
}
processInvokeMethod(InvokeMethod node) {
Selector selector = node.selector;
if (!_glue.isInterceptedSelector(selector)) return;
+ // Some platform libraries will compare non-interceptable objects against
+ // null using the Dart == operator. These must be translated directly.
+ if (node.selector == Selectors.equals &&
+ node.arguments.length == 1 &&
+ isNullConstant(node.arguments[0].definition)) {
+ node.replaceWith(new ApplyBuiltinOperator(
+ BuiltinOperator.Identical,
+ [node.receiver.definition, node.arguments[0].definition],
+ node.sourceInformation));
+ return;
+ }
+
Primitive receiver = node.receiver.definition;
Primitive newReceiver;
@@ -227,17 +219,16 @@
// Change 'receiver.foo()' to 'this.foo(receiver)'.
newReceiver = thisParameter;
} else {
- LetCont contBinding = node.parent;
newReceiver = new Interceptor(receiver, node.sourceInformation)
..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector));
if (receiver.hint != null) {
newReceiver.hint = new InterceptorEntity(receiver.hint);
}
- insertLetPrim(newReceiver, contBinding);
+ new LetPrim(newReceiver).insertAbove(node.parent);
}
node.arguments.insert(0, node.receiver);
node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
- node.receiverIsIntercepted = true;
+ node.callingConvention = CallingConvention.Intercepted;
}
processInvokeMethodDirectly(InvokeMethodDirectly node) {
@@ -253,16 +244,16 @@
// Change 'receiver.foo()' to 'this.foo(receiver)'.
newReceiver = thisParameter;
} else {
- LetCont contBinding = node.parent;
newReceiver = new Interceptor(receiver, node.sourceInformation)
..interceptedClasses.addAll(_glue.getInterceptedClassesOn(selector));
if (receiver.hint != null) {
newReceiver.hint = new InterceptorEntity(receiver.hint);
}
- insertLetPrim(newReceiver, contBinding);
+ new LetPrim(newReceiver).insertAbove(node.parent);
}
node.arguments.insert(0, node.receiver);
node.receiver = new Reference<Primitive>(newReceiver)..parent = node;
+ node.callingConvention = CallingConvention.Intercepted;
}
processInterceptor(Interceptor node) {
diff --git a/pkg/compiler/lib/src/js_backend/js_backend.dart b/pkg/compiler/lib/src/js_backend/js_backend.dart
index 9c69c45..99d383c 100644
--- a/pkg/compiler/lib/src/js_backend/js_backend.dart
+++ b/pkg/compiler/lib/src/js_backend/js_backend.dart
@@ -47,6 +47,10 @@
CoreClasses,
CoreTypes;
import '../dart_types.dart';
+import '../deferred_load.dart' show
+ DeferredLoadTask;
+import '../dump_info.dart' show
+ DumpInfoTask;
import '../elements/elements.dart';
import '../elements/visitor.dart' show
BaseElementVisitor;
@@ -92,8 +96,11 @@
TypeUse,
TypeUseKind;
import '../universe/world_impact.dart' show
+ ImpactStrategy,
+ ImpactUseCase,
TransformedWorldImpact,
- WorldImpact;
+ WorldImpact,
+ WorldImpactVisitor;
import '../util/characters.dart';
import '../util/util.dart';
import '../world.dart' show
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index 65a49c8..ad5c04c 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -120,6 +120,10 @@
ClassElement classElement = element;
+ // Skip classes that are completely unreachable. This should only happen
+ // when all of jsinterop types are unreachable from main.
+ if (!backend.compiler.world.isImplemented(classElement)) return;
+
if (!classElement
.implementsInterface(helpers.jsJavaScriptObjectClass)) {
backend.reporter.reportErrorMessage(classElement,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
index 3a84f11..894bd92 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/field_visitor.dart
@@ -149,7 +149,7 @@
if (field.isFinal || field.isConst) return false;
if (backend.shouldRetainSetter(field)) return true;
return field.isClassMember &&
- compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
+ compiler.codegenWorld.hasInvokedSetter(field, compiler.world);
}
static bool fieldAccessNeverThrows(VariableElement field) {
diff --git a/pkg/compiler/lib/src/native/behavior.dart b/pkg/compiler/lib/src/native/behavior.dart
index 7dbab30..438dbe6 100644
--- a/pkg/compiler/lib/src/native/behavior.dart
+++ b/pkg/compiler/lib/src/native/behavior.dart
@@ -140,9 +140,15 @@
///
/// 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 @@
/// 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 @@
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>{
@@ -645,12 +658,26 @@
static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
FunctionType type = method.computeType(compiler.resolution);
var behavior = new NativeBehavior();
- behavior.typesReturned.add(type.returnType);
+ var returnType = type.returnType;
+ bool isInterop = compiler.backend.isJsInterop(method);
+ // Note: For dart:html and other internal libraries we maintain, we can
+ // trust the return type and use it to limit what we enqueue. We have to
+ // be more conservative about JS interop types and assume they can return
+ // anything (unless the user provides the experimental flag to trust the
+ // type of js-interop APIs). We do restrict the allocation effects and say
+ // that interop calls create only interop types (which may be unsound if
+ // an interop call returns a DOM type and declares a dynamic return type,
+ // but otherwise we would include a lot of code by default).
+ // TODO(sigmund,sra): consider doing something better for numeric types.
+ behavior.typesReturned.add(
+ !isInterop || compiler.trustJSInteropTypeAnnotations ? returnType
+ : const DynamicType());
if (!type.returnType.isVoid) {
// Declared types are nullable.
behavior.typesReturned.add(compiler.coreTypes.nullType);
}
- behavior._capture(type, compiler.resolution);
+ behavior._capture(type, compiler.resolution,
+ isInterop: isInterop, compiler: compiler);
// TODO(sra): Optional arguments are currently missing from the
// DartType. This should be fixed so the following work-around can be
@@ -668,10 +695,15 @@
Resolution resolution = compiler.resolution;
DartType type = field.computeType(resolution);
var behavior = new NativeBehavior();
- behavior.typesReturned.add(type);
+ bool isInterop = compiler.backend.isJsInterop(field);
+ // TODO(sigmund,sra): consider doing something better for numeric types.
+ behavior.typesReturned.add(
+ !isInterop || compiler.trustJSInteropTypeAnnotations ? type
+ : const DynamicType());
// Declared types are nullable.
behavior.typesReturned.add(resolution.coreTypes.nullType);
- behavior._capture(type, resolution);
+ behavior._capture(type, resolution,
+ isInterop: isInterop, compiler: compiler);
behavior._overrideWithAnnotations(field, compiler);
return behavior;
}
@@ -765,17 +797,50 @@
/// Models the behavior of Dart code receiving instances and methods of [type]
/// from native code. We usually start the analysis by capturing a native
/// method that has been used.
- void _capture(DartType type, Resolution resolution) {
+ ///
+ /// We assume that JS-interop APIs cannot instantiate Dart types or
+ /// non-JSInterop native types.
+ void _capture(DartType type, Resolution resolution,
+ {bool isInterop: false, Compiler compiler}) {
type.computeUnaliased(resolution);
type = type.unaliased;
if (type is FunctionType) {
FunctionType functionType = type;
- _capture(functionType.returnType, resolution);
+ _capture(functionType.returnType, resolution,
+ isInterop: isInterop, compiler: compiler);
for (DartType parameter in functionType.parameterTypes) {
_escape(parameter, resolution);
}
} else {
- typesInstantiated.add(type);
+ DartType instantiated = null;
+ JavaScriptBackend backend = compiler?.backend;
+ if (!isInterop) {
+ typesInstantiated.add(type);
+ } else {
+ if (type.element != null && backend.isNative(type.element)) {
+ // Any declared native or interop type (isNative implies isJsInterop)
+ // is assumed to be allocated.
+ typesInstantiated.add(type);
+ }
+
+ if (!compiler.trustJSInteropTypeAnnotations ||
+ type.isDynamic || type.isObject) {
+ // By saying that only JS-interop types can be created, we prevent
+ // pulling in every other native type (e.g. all of dart:html) when a
+ // JS interop API returns dynamic or when we don't trust the type
+ // annotations. This means that to some degree we still use the return
+ // type to decide whether to include native types, even if we don't
+ // trust the type annotation.
+ ClassElement cls = backend.helpers.jsJavaScriptObjectClass;
+ cls.ensureResolved(resolution);
+ typesInstantiated.add(cls.thisType);
+ } else {
+ // Otherwise, when the declared type is a Dart type, we do not
+ // register an allocation because we assume it cannot be instantiated
+ // from within the JS-interop code. It must have escaped from another
+ // API.
+ }
+ }
}
}
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 6d41d9c..c41d5a1 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -3361,13 +3361,14 @@
registry.registerStaticUse(new StaticUse.superGet(semantics.getter));
break;
case AccessKind.SUPER_SETTER:
- registry.registerStaticUse(new StaticUse.superSet(semantics.setter));
+ registry.registerStaticUse(
+ new StaticUse.superSetterSet(semantics.setter));
break;
case AccessKind.SUPER_FIELD:
registry.registerStaticUse(
new StaticUse.superGet(semantics.element));
registry.registerStaticUse(
- new StaticUse.superSet(semantics.element));
+ new StaticUse.superFieldSet(semantics.element));
break;
case AccessKind.SUPER_FINAL_FIELD:
registry.registerStaticUse(
@@ -3376,22 +3377,27 @@
case AccessKind.COMPOUND:
CompoundAccessSemantics compoundSemantics = semantics;
switch (compoundSemantics.compoundAccessKind) {
- case CompoundAccessKind.SUPER_GETTER_SETTER:
case CompoundAccessKind.SUPER_GETTER_FIELD:
- case CompoundAccessKind.SUPER_FIELD_SETTER:
case CompoundAccessKind.SUPER_FIELD_FIELD:
registry.registerStaticUse(
new StaticUse.superGet(semantics.getter));
registry.registerStaticUse(
- new StaticUse.superSet(semantics.setter));
+ new StaticUse.superFieldSet(semantics.setter));
+ break;
+ case CompoundAccessKind.SUPER_FIELD_SETTER:
+ case CompoundAccessKind.SUPER_GETTER_SETTER:
+ registry.registerStaticUse(
+ new StaticUse.superGet(semantics.getter));
+ registry.registerStaticUse(
+ new StaticUse.superSetterSet(semantics.setter));
break;
case CompoundAccessKind.SUPER_METHOD_SETTER:
registry.registerStaticUse(
- new StaticUse.superSet(semantics.setter));
+ new StaticUse.superSetterSet(semantics.setter));
break;
case CompoundAccessKind.UNRESOLVED_SUPER_GETTER:
registry.registerStaticUse(
- new StaticUse.superSet(semantics.setter));
+ new StaticUse.superSetterSet(semantics.setter));
break;
case CompoundAccessKind.UNRESOLVED_SUPER_SETTER:
registry.registerStaticUse(
@@ -3446,9 +3452,12 @@
registry.registerFeature(Feature.SUPER_NO_SUCH_METHOD);
break;
case AccessKind.SUPER_FIELD:
+ registry.registerStaticUse(
+ new StaticUse.superFieldSet(semantics.setter));
+ break;
case AccessKind.SUPER_SETTER:
registry.registerStaticUse(
- new StaticUse.superSet(semantics.setter));
+ new StaticUse.superSetterSet(semantics.setter));
break;
default:
break;
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 0945568..540ba50 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5134,15 +5134,23 @@
stack.add(graph.addConstantNull(compiler));
return;
}
+
if (checkTypeVariableBounds(node, type)) return;
- var inputs = <HInstruction>[];
- if (constructor.isGenerativeConstructor &&
- backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
- !backend.isJsInterop(constructor)) {
- // Native class generative constructors take a pre-constructed object.
- inputs.add(graph.addConstantNull(compiler));
+ // Abstract class instantiation error takes precedence over argument
+ // mismatch.
+ ClassElement cls = constructor.enclosingClass;
+ if (cls.isAbstract && constructor.isGenerativeConstructor) {
+ // However, we need to ensure that all arguments are evaluated before we
+ // throw the ACIE exception.
+ send.arguments.forEach((arg) {
+ visit(arg);
+ pop();
+ });
+ generateAbstractClassInstantiationError(send, cls.name);
+ return;
}
+
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [makeStaticArgumentList].
constructorImplementation = constructor.implementation;
@@ -5152,6 +5160,14 @@
generateWrongArgumentCountError(send, constructor, send.arguments);
return;
}
+
+ var inputs = <HInstruction>[];
+ if (constructor.isGenerativeConstructor &&
+ backend.isNativeOrExtendsNative(constructor.enclosingClass) &&
+ !backend.isJsInterop(constructor)) {
+ // Native class generative constructors take a pre-constructed object.
+ inputs.add(graph.addConstantNull(compiler));
+ }
inputs.addAll(makeStaticArgumentList(callStructure,
send.arguments,
constructorImplementation));
@@ -5198,13 +5214,7 @@
} else {
SourceInformation sourceInformation =
sourceInformationBuilder.buildNew(send);
- ClassElement cls = constructor.enclosingClass;
- if (cls.isAbstract && constructor.isGenerativeConstructor) {
- generateAbstractClassInstantiationError(send, cls.name);
- return;
- }
potentiallyAddTypeArguments(inputs, cls, expectedType);
-
addInlinedInstantiation(expectedType);
pushInvokeStatic(node, constructor, inputs,
typeMask: elementType,
@@ -5864,7 +5874,7 @@
&& params.optionalParametersAreNamed;
}
- HForeignCode invokeJsInteropFunction(Element element,
+ HForeignCode invokeJsInteropFunction(FunctionElement element,
List<HInstruction> arguments,
SourceInformation sourceInformation) {
assert(backend.isJsInterop(element));
@@ -5898,6 +5908,9 @@
var nativeBehavior = new native.NativeBehavior()
..codeTemplate = codeTemplate;
+ if (compiler.trustJSInteropTypeAnnotations) {
+ nativeBehavior.typesReturned.add(constructor.enclosingClass.thisType);
+ }
return new HForeignCode(
codeTemplate,
backend.dynamicType, filteredArguments,
@@ -5917,34 +5930,43 @@
arguments = arguments.where((arg) => arg != null).toList();
var inputs = <HInstruction>[target]..addAll(arguments);
- js.Template codeTemplate;
- if (element.isGetter) {
- codeTemplate = js.js.parseForeignJS("#");
- } else if (element.isSetter) {
- codeTemplate = js.js.parseForeignJS("# = #");
- } else {
- FunctionElement function = element;
- FunctionSignature params = function.functionSignature;
+ var nativeBehavior = new native.NativeBehavior()
+ ..sideEffects.setAllSideEffects();
- var argsStub = <String>[];
- for (int i = 0; i < arguments.length; i++) {
- argsStub.add('#');
- }
+ DartType type = element.isConstructor ?
+ element.enclosingClass.thisType : element.type.returnType;
+ // Native behavior effects here are similar to native/behavior.dart.
+ // The return type is dynamic if we don't trust js-interop type
+ // declarations.
+ nativeBehavior.typesReturned.add(
+ compiler.trustJSInteropTypeAnnotations ? type : const DynamicType());
- if (element.isConstructor) {
- codeTemplate = js.js.parseForeignJS("new #(${argsStub.join(",")})");
- } else {
- codeTemplate = js.js.parseForeignJS("#(${argsStub.join(",")})");
- }
+ // The allocation effects include the declared type if it is native (which
+ // includes js interop types).
+ if (type.element != null && backend.isNative(type.element)) {
+ nativeBehavior.typesInstantiated.add(type);
}
- var nativeBehavior = new native.NativeBehavior()
- ..codeTemplate = codeTemplate
- ..typesReturned.add(
- helpers.jsJavaScriptObjectClass.thisType)
- ..typesInstantiated.add(
- helpers.jsJavaScriptObjectClass.thisType)
- ..sideEffects.setAllSideEffects();
+ // It also includes any other JS interop type if we don't trust the
+ // annotation or if is declared too broad.
+ if (!compiler.trustJSInteropTypeAnnotations || type.isObject ||
+ type.isDynamic) {
+ nativeBehavior.typesInstantiated.add(
+ backend.helpers.jsJavaScriptObjectClass.thisType);
+ }
+
+ String code;
+ if (element.isGetter) {
+ code = "#";
+ } else if (element.isSetter) {
+ code = "# = #";
+ } else {
+ var args = new List.filled(arguments.length, '#').join(',');
+ code = element.isConstructor ? "new #($args)" : "#($args)";
+ }
+ js.Template codeTemplate = js.js.parseForeignJS(code);
+ nativeBehavior.codeTemplate = codeTemplate;
+
return new HForeignCode(
codeTemplate,
backend.dynamicType, inputs,
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 69ee9c8..688030a 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -1751,7 +1751,9 @@
.withSourceInformation(node.sourceInformation);
if (node.isSetter) {
registry.registerStaticUse(
- new StaticUse.superSet(superElement));
+ superElement.isSetter
+ ? new StaticUse.superSetterSet(superElement)
+ : new StaticUse.superFieldSet(superElement));
use(node.value);
push(new js.Assignment(access, pop())
.withSourceInformation(node.sourceInformation));
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
index 4f0be4a..b4f6dd8 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/logical_rewriter.dart
@@ -63,11 +63,6 @@
final FallthroughStack fallthrough = new FallthroughStack();
- @override
- void visitInnerFunction(FunctionDefinition node) {
- new LogicalRewriter().rewrite(node);
- }
-
/// True if the given statement is equivalent to its fallthrough semantics.
///
/// This means it will ultimately translate to an empty statement.
@@ -543,9 +538,9 @@
}
}
- /// True if [e2] is known to return the same value as [e1]
+ /// True if [e2] is known to return the same value as [e1]
/// (with no additional side effects) if evaluated immediately after [e1].
- ///
+ ///
/// Concretely, this is true if [e1] and [e2] are uses of the same variable,
/// or if [e2] is a use of a variable assigned by [e1].
bool isSameVariable(Expression e1, Expression e2) {
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
index 14069e8..2f5a9fd 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/loop_rewriter.dart
@@ -52,13 +52,13 @@
///
/// Note that the pattern above needs no iteration since nested ifs have been
/// collapsed previously in the [StatementRewriter] phase.
-///
+///
///
/// PULL INTO UPDATE EXPRESSION:
-///
+///
/// Assignment expressions before the unique continue to a [whileCondition] are
/// pulled into the updates for the loop.
-///
+///
/// L:
/// for (; condition; updates) {
/// S [ x = E; continue L ]
@@ -69,7 +69,7 @@
/// S [ continue L ]
/// }
///
-/// The decision to only pull in assignments is a heuristic to balance
+/// The decision to only pull in assignments is a heuristic to balance
/// readability and stack trace usability versus the modest code size
/// reduction one might get by aggressively moving expressions into the
/// updates.
@@ -88,11 +88,6 @@
root.body = visitStatement(root.body);
}
- @override
- void visitInnerFunction(FunctionDefinition node) {
- node.body = new LoopRewriter().visitStatement(node.body);
- }
-
Statement visitContinue(Continue node) {
usedContinueLabels.add(node.target);
return node;
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
index 878d8e1..18bab39 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/pull_into_initializers.dart
@@ -338,15 +338,6 @@
return node;
}
- void visitInnerFunction(FunctionDefinition node) {
- new PullIntoInitializers().rewrite(node);
- }
-
- Expression visitFunctionExpression(FunctionExpression node) {
- visitInnerFunction(node.definition);
- return node;
- }
-
Expression visitApplyBuiltinOperator(ApplyBuiltinOperator node) {
rewriteList(node.arguments);
return node;
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
index 1da49af..6667ded 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/statement_rewriter.dart
@@ -579,11 +579,6 @@
return node;
}
- Expression visitFunctionExpression(FunctionExpression node) {
- new StatementRewriter.nested(this).rewrite(node.definition);
- return node;
- }
-
Statement visitReturn(Return node) {
node.value = visitExpression(node.value);
return node;
@@ -1256,8 +1251,6 @@
wasFound = true;
}
}
-
- visitInnerFunction(FunctionDefinition node) {}
}
typedef VariableUseCallback(VariableUse use);
@@ -1269,8 +1262,6 @@
visitVariableUse(VariableUse use) => callback(use);
- visitInnerFunction(FunctionDefinition node) {}
-
static void visit(Expression node, VariableUseCallback callback) {
new VariableUseVisitor(callback).visitExpression(node);
}
diff --git a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
index 91a5aac..fb31f02 100644
--- a/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
+++ b/pkg/compiler/lib/src/tree_ir/optimization/variable_merger.dart
@@ -20,11 +20,6 @@
visitStatement(node.body);
}
- @override
- void visitInnerFunction(FunctionDefinition node) {
- rewriteFunction(node);
- }
-
/// Rewrites the given function.
/// This is called for the outermost function and inner functions.
void rewriteFunction(FunctionDefinition node) {
@@ -112,11 +107,6 @@
visitStatement(node.body);
}
- @override
- void visitInnerFunction(FunctionDefinition node) {
- // Do nothing. Inner functions are traversed in VariableMerger.
- }
-
/// Creates a new block with the current exception handler or [catchBlock]
/// if provided.
Block newBlock({Block catchBlock}) {
@@ -506,11 +496,6 @@
node.body = visitStatement(node.body);
}
- @override
- void visitInnerFunction(FunctionDefinition node) {
- // Do nothing. Inner functions are traversed in VariableMerger.
- }
-
Expression visitVariableUse(VariableUse node) {
node.variable = replaceRead(node.variable);
return node;
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
index c42cab8..84c5200 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_builder.dart
@@ -117,13 +117,8 @@
return labels.putIfAbsent(cont, () => new Label());
}
- Variable addFunctionParameter(cps_ir.Definition variable) {
- if (variable is cps_ir.Parameter) {
- return getVariable(variable);
- } else {
- return addMutableVariable(variable as cps_ir.MutableVariable)
- ..isCaptured = true;
- }
+ Variable addFunctionParameter(cps_ir.Parameter parameter) {
+ return getVariable(parameter);
}
FunctionDefinition buildFunction(cps_ir.FunctionDefinition node) {
@@ -273,7 +268,7 @@
/// Translates a CPS primitive to a tree expression.
///
/// This simply calls the visit method for the primitive.
- Expression translatePrimitive(cps_ir.Primitive prim) {
+ translatePrimitive(cps_ir.Primitive prim) {
return prim.accept(this);
}
@@ -284,15 +279,20 @@
// (Statement next) => <result statement>
//
- NodeCallback visitLetPrim(cps_ir.LetPrim node) => (Statement next) {
+ NodeCallback visitLetPrim(cps_ir.LetPrim node) {
Variable variable = getVariable(node.primitive);
- Expression value = translatePrimitive(node.primitive);
- if (node.primitive.hasAtLeastOneUse) {
- return Assign.makeStatement(variable, value, next);
+ var value = translatePrimitive(node.primitive);
+ if (value is Expression) {
+ if (node.primitive.hasAtLeastOneUse) {
+ return (Statement next) => Assign.makeStatement(variable, value, next);
+ } else {
+ return (Statement next) => new ExpressionStatement(value, next);
+ }
} else {
- return new ExpressionStatement(value, next);
+ assert(value is NodeCallback);
+ return value;
}
- };
+ }
// Continuations are bound at the same level, but they have to be
// translated as if nested. This is because the body can invoke any
@@ -338,128 +338,6 @@
return (Statement next) => Assign.makeStatement(variable, value, next);
}
-
- /************************ CALL EXPRESSIONS ************************/
- //
- // Visit methods for call expressions must return a function:
- //
- // (Statement next) => <result statement>
- //
- // The result statement must include an assignment to the continuation
- // parameter, if the parameter is used.
- //
-
- NodeCallback makeCallExpression(cps_ir.CallExpression call,
- Expression expression) {
- return (Statement next) {
- cps_ir.Parameter result = call.continuation.definition.parameters.single;
- if (result.hasAtLeastOneUse) {
- return Assign.makeStatement(getVariable(result), expression, next);
- } else {
- return new ExpressionStatement(expression, next);
- }
- };
- }
-
- NodeCallback visitInvokeStatic(cps_ir.InvokeStatic node) {
- List<Expression> arguments = translateArguments(node.arguments);
- Expression invoke = new InvokeStatic(node.target, node.selector, arguments,
- node.sourceInformation);
- return makeCallExpression(node, invoke);
- }
-
- NodeCallback visitInvokeMethod(cps_ir.InvokeMethod node) {
- InvokeMethod invoke = new InvokeMethod(
- getVariableUse(node.receiver),
- node.selector,
- node.mask,
- translateArguments(node.arguments),
- node.sourceInformation);
- invoke.receiverIsNotNull = node.receiverIsNotNull;
- return makeCallExpression(node, invoke);
- }
-
- NodeCallback visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
- Expression receiver = getVariableUse(node.receiver);
- List<Expression> arguments = translateArguments(node.arguments);
- Expression invoke = new InvokeMethodDirectly(receiver, node.target,
- node.selector, arguments, node.sourceInformation);
- return makeCallExpression(node, invoke);
- }
-
- NodeCallback visitTypeCast(cps_ir.TypeCast node) {
- Expression value = getVariableUse(node.value);
- List<Expression> typeArgs = translateArguments(node.typeArguments);
- Expression expression =
- new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
- return makeCallExpression(node, expression);
- }
-
- NodeCallback visitInvokeConstructor(cps_ir.InvokeConstructor node) {
- List<Expression> arguments = translateArguments(node.arguments);
- Expression invoke = new InvokeConstructor(
- node.dartType,
- node.target,
- node.selector,
- arguments,
- node.sourceInformation);
- return makeCallExpression(node, invoke);
- }
-
- NodeCallback visitForeignCode(cps_ir.ForeignCode node) {
- List<Expression> arguments =
- node.arguments.map(getVariableUse).toList(growable: false);
- if (HasCapturedArguments.check(node.codeTemplate.ast)) {
- for (Expression arg in arguments) {
- if (arg is VariableUse) {
- arg.variable.isCaptured = true;
- } else {
- // TODO(asgerf): Avoid capture of 'this'.
- }
- }
- }
- if (node.codeTemplate.isExpression) {
- Expression foreignCode = new ForeignExpression(
- node.codeTemplate,
- node.type,
- arguments,
- node.nativeBehavior,
- node.dependency);
- return makeCallExpression(node, foreignCode);
- } else {
- return (Statement next) {
- assert(next is Unreachable); // We are not using the `next` statement.
- return new ForeignStatement(
- node.codeTemplate,
- node.type,
- arguments,
- node.nativeBehavior,
- node.dependency);
- };
- }
- }
-
- NodeCallback visitGetLazyStatic(cps_ir.GetLazyStatic node) {
- // In the tree IR, GetStatic handles lazy fields because we do not need
- // as fine-grained control over side effects.
- GetStatic value = new GetStatic(node.element, node.sourceInformation);
- return makeCallExpression(node, value);
- }
-
- @override
- NodeCallback visitYield(cps_ir.Yield node) {
- return (Statement next) {
- return new Yield(getVariableUse(node.input), node.hasStar, next);
- };
- }
-
- @override
- NodeCallback visitAwait(cps_ir.Await node) {
- Expression value = new Await(getVariableUse(node.input));
- return makeCallExpression(node, value);
- }
-
-
/************************** TAIL EXPRESSIONS **************************/
//
// Visit methods for tail expressions must return a statement directly
@@ -622,11 +500,6 @@
return createInnerBuilder().buildFunction(function);
}
- Expression visitCreateFunction(cps_ir.CreateFunction node) {
- FunctionDefinition def = makeSubFunction(node.definition);
- return new FunctionExpression(def);
- }
-
Expression visitReifyRuntimeType(cps_ir.ReifyRuntimeType node) {
return new ReifyRuntimeType(
getVariableUse(node.value), node.sourceInformation);
@@ -698,6 +571,96 @@
getVariableUse(node.value));
}
+ Expression visitInvokeStatic(cps_ir.InvokeStatic node) {
+ List<Expression> arguments = translateArguments(node.arguments);
+ return new InvokeStatic(node.target, node.selector, arguments,
+ node.sourceInformation);
+ }
+
+ Expression visitInvokeMethod(cps_ir.InvokeMethod node) {
+ InvokeMethod invoke = new InvokeMethod(
+ getVariableUse(node.receiver),
+ node.selector,
+ node.mask,
+ translateArguments(node.arguments),
+ node.sourceInformation);
+ invoke.receiverIsNotNull = node.receiverIsNotNull;
+ return invoke;
+ }
+
+ Expression visitInvokeMethodDirectly(cps_ir.InvokeMethodDirectly node) {
+ Expression receiver = getVariableUse(node.receiver);
+ List<Expression> arguments = translateArguments(node.arguments);
+ return new InvokeMethodDirectly(receiver, node.target,
+ node.selector, arguments, node.sourceInformation);
+ }
+
+ Expression visitTypeCast(cps_ir.TypeCast node) {
+ Expression value = getVariableUse(node.value);
+ List<Expression> typeArgs = translateArguments(node.typeArguments);
+ return new TypeOperator(value, node.dartType, typeArgs, isTypeTest: false);
+ }
+
+ Expression visitInvokeConstructor(cps_ir.InvokeConstructor node) {
+ List<Expression> arguments = translateArguments(node.arguments);
+ return new InvokeConstructor(
+ node.dartType,
+ node.target,
+ node.selector,
+ arguments,
+ node.sourceInformation);
+ }
+
+ visitForeignCode(cps_ir.ForeignCode node) {
+ List<Expression> arguments =
+ node.arguments.map(getVariableUse).toList(growable: false);
+ if (HasCapturedArguments.check(node.codeTemplate.ast)) {
+ for (Expression arg in arguments) {
+ if (arg is VariableUse) {
+ arg.variable.isCaptured = true;
+ } else {
+ // TODO(asgerf): Avoid capture of 'this'.
+ }
+ }
+ }
+ if (node.codeTemplate.isExpression) {
+ return new ForeignExpression(
+ node.codeTemplate,
+ node.type,
+ arguments,
+ node.nativeBehavior,
+ node.dependency);
+ } else {
+ return (Statement next) {
+ assert(next is Unreachable); // We are not using the `next` statement.
+ return new ForeignStatement(
+ node.codeTemplate,
+ node.type,
+ arguments,
+ node.nativeBehavior,
+ node.dependency);
+ };
+ }
+ }
+
+ Expression visitGetLazyStatic(cps_ir.GetLazyStatic node) {
+ // In the tree IR, GetStatic handles lazy fields because we do not need
+ // as fine-grained control over side effects.
+ return new GetStatic(node.element, node.sourceInformation);
+ }
+
+ @override
+ NodeCallback visitYield(cps_ir.Yield node) {
+ return (Statement next) {
+ return new Yield(getVariableUse(node.input), node.hasStar, next);
+ };
+ }
+
+ @override
+ Expression visitAwait(cps_ir.Await node) {
+ return new Await(getVariableUse(node.input));
+ }
+
@override
Expression visitRefinement(cps_ir.Refinement node) {
throw 'Unexpected Refinement node in tree builder';
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
index 3a1a0bc..691a330 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_integrity.dart
@@ -129,10 +129,6 @@
labelUses[node.target]++;
}
- visitInnerFunction(FunctionDefinition node) {
- checkBody(node);
- }
-
void checkBody(FunctionDefinition node) {
node.parameters.forEach(declare);
visitStatement(node.body);
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index bd4baab..80e4f28 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -114,7 +114,6 @@
/// Number of places where this variable occurs as:
/// - left-hand of an [Assign]
- /// - left-hand of a [FunctionDeclaration]
/// - parameter in a [FunctionDefinition]
/// - catch parameter in a [Try]
int writeCount = 0;
@@ -437,20 +436,6 @@
accept1(ExpressionVisitor1 visitor, arg) => visitor.visitNot(this, arg);
}
-/// Currently unused.
-///
-/// See CreateFunction in the cps_ir_nodes.dart.
-class FunctionExpression extends Expression {
- final FunctionDefinition definition;
-
- FunctionExpression(this.definition);
-
- accept(ExpressionVisitor visitor) => visitor.visitFunctionExpression(this);
- accept1(ExpressionVisitor1 visitor, arg) {
- return visitor.visitFunctionExpression(this, arg);
- }
-}
-
/// A [LabeledStatement] or [WhileTrue] or [For].
abstract class JumpTarget extends Statement {
Label get label;
@@ -988,7 +973,6 @@
E visitLiteralList(LiteralList node);
E visitLiteralMap(LiteralMap node);
E visitTypeOperator(TypeOperator node);
- E visitFunctionExpression(FunctionExpression node);
E visitGetField(GetField node);
E visitSetField(SetField node);
E visitGetStatic(GetStatic node);
@@ -1026,7 +1010,6 @@
E visitLiteralList(LiteralList node, A arg);
E visitLiteralMap(LiteralMap node, A arg);
E visitTypeOperator(TypeOperator node, A arg);
- E visitFunctionExpression(FunctionExpression node, A arg);
E visitGetField(GetField node, A arg);
E visitSetField(SetField node, A arg);
E visitGetStatic(GetStatic node, A arg);
@@ -1088,8 +1071,6 @@
visitExpression(Expression e) => e.accept(this);
visitStatement(Statement s) => s.accept(this);
- visitInnerFunction(FunctionDefinition node);
-
visitVariable(Variable variable) {}
visitVariableUse(VariableUse node) {
@@ -1154,10 +1135,6 @@
node.typeArguments.forEach(visitExpression);
}
- visitFunctionExpression(FunctionExpression node) {
- visitInnerFunction(node.definition);
- }
-
visitLabeledStatement(LabeledStatement node) {
visitStatement(node.body);
visitStatement(node.next);
@@ -1309,10 +1286,6 @@
}
class RecursiveTransformer extends Transformer {
- void visitInnerFunction(FunctionDefinition node) {
- node.body = visitStatement(node.body);
- }
-
void _replaceExpressions(List<Expression> list) {
for (int i = 0; i < list.length; i++) {
list[i] = visitExpression(list[i]);
@@ -1389,11 +1362,6 @@
return node;
}
- visitFunctionExpression(FunctionExpression node) {
- visitInnerFunction(node.definition);
- return node;
- }
-
visitLabeledStatement(LabeledStatement node) {
node.body = visitStatement(node.body);
node.next = visitStatement(node.next);
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
index 130d268..3f08e95 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_tracer.dart
@@ -464,10 +464,6 @@
return '!$operand';
}
- String visitFunctionExpression(FunctionExpression node) {
- return "function ${node.definition.element.name}";
- }
-
String visitGetField(GetField node) {
String object = visitExpression(node.object);
String field = node.field.name;
diff --git a/pkg/compiler/lib/src/types/abstract_value_domain.dart b/pkg/compiler/lib/src/types/abstract_value_domain.dart
new file mode 100644
index 0000000..14c9939
--- /dev/null
+++ b/pkg/compiler/lib/src/types/abstract_value_domain.dart
@@ -0,0 +1,164 @@
+// 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 dart2js.abstract_value_domain;
+
+import '../constants/values.dart';
+import '../dart_types.dart';
+import '../elements/elements.dart';
+import '../native/native.dart' show
+ NativeBehavior;
+import '../universe/selector.dart' show
+ Selector;
+import '../universe/universe.dart' show
+ ReceiverConstraint;
+
+enum AbstractBool {
+ True, False, Maybe, Nothing
+}
+
+/// A value in an abstraction of runtime values.
+abstract class AbstractValue {}
+
+/// A system that implements an abstraction over runtime values and provides
+/// access to interprocedural analysis results.
+// TODO(johnniwinther): Consider extracting the inference result access from
+// this interface.
+abstract class AbstractValueDomain {
+ AbstractValue get dynamicType;
+ AbstractValue get typeType;
+ AbstractValue get functionType;
+ AbstractValue get boolType;
+ AbstractValue get intType;
+ AbstractValue get doubleType;
+ AbstractValue get numType;
+ AbstractValue get stringType;
+ AbstractValue get listType;
+ AbstractValue get mapType;
+ AbstractValue get nonNullType;
+ AbstractValue get nullType;
+ AbstractValue get extendableArrayType;
+ AbstractValue get fixedArrayType;
+ AbstractValue get arrayType;
+ AbstractValue get uint31Type;
+ AbstractValue get uint32Type;
+ AbstractValue get uintType;
+
+ AbstractValue get numStringBoolType;
+
+ AbstractValue get fixedLengthType;
+
+ AbstractValue get interceptorType;
+
+ AbstractValue get interceptedTypes;
+
+ bool methodUsesReceiverArgument(FunctionElement function);
+
+ Element locateSingleElement(AbstractValue mask, Selector selector);
+
+ ClassElement singleClass(AbstractValue mask);
+
+ bool needsNoSuchMethodHandling(AbstractValue mask, Selector selector);
+
+ AbstractValue getReceiverType(MethodElement method);
+
+ AbstractValue getParameterType(ParameterElement parameter);
+
+ AbstractValue getReturnType(FunctionElement function);
+
+ AbstractValue getInvokeReturnType(Selector selector, AbstractValue mask);
+
+ AbstractValue getFieldType(FieldElement field);
+
+ AbstractValue join(AbstractValue a, AbstractValue b);
+
+ AbstractValue intersection(AbstractValue a, AbstractValue b);
+
+ AbstractValue getTypeOf(ConstantValue constant);
+
+ /// Returns the constant value if the [AbstractValue] represents a single
+ /// constant value. Returns `null` if [value] is not a constant.
+ ConstantValue getConstantOf(AbstractValue value);
+
+ AbstractValue nonNullExact(ClassElement element);
+
+ AbstractValue nonNullSubclass(ClassElement element);
+
+ AbstractValue nonNullSubtype(ClassElement element);
+
+ bool isDefinitelyBool(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyNum(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyString(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyNumStringBool(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyNotNumStringBool(AbstractValue t);
+
+ /// True if all values of [t] are either integers or not numbers at all.
+ ///
+ /// This does not imply that the value is an integer, since most other values
+ /// such as null are also not a non-integer double.
+ bool isDefinitelyNotNonIntegerDouble(AbstractValue t);
+
+ bool isDefinitelyNonNegativeInt(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyInt(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyUint31(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyUint32(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyUint(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyArray(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyMutableArray(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyFixedArray(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyExtendableArray(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyIndexable(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyMutableIndexable(AbstractValue t, {bool allowNull: false});
+
+ bool isDefinitelyFixedLengthIndexable(AbstractValue t,
+ {bool allowNull: false});
+
+ bool isDefinitelyIntercepted(AbstractValue t, {bool allowNull});
+
+ /// Given a class from the interceptor hierarchy, returns an [AbstractValue]
+ /// matching all values with that interceptor (or a subtype thereof).
+ AbstractValue getInterceptorSubtypes(ClassElement class_);
+
+ bool areDisjoint(AbstractValue leftType, AbstractValue rightType);
+
+ bool isMorePreciseOrEqual(AbstractValue t1, AbstractValue t2);
+
+ AbstractBool isSubtypeOf(AbstractValue value,
+ DartType type,
+ {bool allowNull});
+
+ /// Returns whether [value] is one of the falsy values: false, 0, -0, NaN,
+ /// the empty string, or null.
+ AbstractBool boolify(AbstractValue value);
+
+ AbstractBool strictBoolify(AbstractValue type);
+
+ /// Create a type mask containing at least all subtypes of [type].
+ AbstractValue subtypesOf(DartType type);
+
+ /// Returns a subset of [receiver] containing at least the types
+ /// that can respond to [selector] without throwing.
+ AbstractValue receiverTypeFor(Selector selector, AbstractValue receiver);
+
+ /// The result of an index operation on [value], or the dynamic type if
+ /// unknown.
+ AbstractValue elementTypeOfIndexable(AbstractValue value);
+
+ /// The length property of [value], or `null` if unknown.
+ int getContainerLength(AbstractValue value);
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/types/type_mask.dart b/pkg/compiler/lib/src/types/type_mask.dart
index c255b60..3339738 100644
--- a/pkg/compiler/lib/src/types/type_mask.dart
+++ b/pkg/compiler/lib/src/types/type_mask.dart
@@ -75,7 +75,7 @@
* operations on it are not guaranteed to be precise and they may
* yield conservative answers that contain too many classes.
*/
-abstract class TypeMask implements ReceiverConstraint {
+abstract class TypeMask implements ReceiverConstraint, AbstractValue {
factory TypeMask(ClassElement base,
int kind,
bool isNullable,
diff --git a/pkg/compiler/lib/src/types/types.dart b/pkg/compiler/lib/src/types/types.dart
index b8591aa..b9e5969 100644
--- a/pkg/compiler/lib/src/types/types.dart
+++ b/pkg/compiler/lib/src/types/types.dart
@@ -28,6 +28,9 @@
ClassWorld,
World;
+import 'abstract_value_domain.dart' show
+ AbstractValue;
+
part 'container_type_mask.dart';
part 'dictionary_type_mask.dart';
part 'flat_type_mask.dart';
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index 5a7ba20..8b2f53e 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -305,7 +305,9 @@
Map<Selector, SelectorConstraints> selectors = selectorMap.putIfAbsent(
name, () => new Maplet<Selector, SelectorConstraints>());
UniverseSelectorConstraints constraints = selectors.putIfAbsent(
- selector, () => selectorConstraintsStrategy.createSelectorConstraints(selector));
+ selector, () {
+ return selectorConstraintsStrategy.createSelectorConstraints(selector);
+ });
return constraints.addReceiverConstraint(mask);
}
@@ -364,6 +366,7 @@
case StaticUseKind.FIELD_GET:
fieldGetters.add(element);
break;
+ case StaticUseKind.SUPER_FIELD_SET:
case StaticUseKind.FIELD_SET:
fieldSetters.add(element);
break;
diff --git a/pkg/compiler/lib/src/universe/use.dart b/pkg/compiler/lib/src/universe/use.dart
index b619d5a..77c1084 100644
--- a/pkg/compiler/lib/src/universe/use.dart
+++ b/pkg/compiler/lib/src/universe/use.dart
@@ -70,6 +70,7 @@
GENERAL,
STATIC_TEAR_OFF,
SUPER_TEAR_OFF,
+ SUPER_FIELD_SET,
FIELD_GET,
FIELD_SET,
CLOSURE,
@@ -160,12 +161,21 @@
return new StaticUse._(element, StaticUseKind.GENERAL);
}
- /// Write access of a super field or setter [element].
- factory StaticUse.superSet(Element element) {
+ /// Write access of a super field [element].
+ factory StaticUse.superFieldSet(FieldElement element) {
assert(invariant(element, element.isInstanceMember,
message: "Super set element $element must be an instance method."));
- assert(invariant(element, element.isField || element.isSetter,
- message: "Super set element $element must be a field or a setter."));
+ assert(invariant(element, element.isField,
+ message: "Super set element $element must be a field."));
+ return new StaticUse._(element, StaticUseKind.SUPER_FIELD_SET);
+ }
+
+ /// Write access of a super setter [element].
+ factory StaticUse.superSetterSet(SetterElement element) {
+ assert(invariant(element, element.isInstanceMember,
+ message: "Super set element $element must be an instance method."));
+ assert(invariant(element, element.isSetter,
+ message: "Super set element $element must be a setter."));
return new StaticUse._(element, StaticUseKind.GENERAL);
}
diff --git a/pkg/compiler/lib/src/universe/world_impact.dart b/pkg/compiler/lib/src/universe/world_impact.dart
index fe7822d..95980a0 100644
--- a/pkg/compiler/lib/src/universe/world_impact.dart
+++ b/pkg/compiler/lib/src/universe/world_impact.dart
@@ -34,6 +34,12 @@
Iterable<TypeUse> get typeUses => const <TypeUse>[];
+ void apply(WorldImpactVisitor visitor) {
+ staticUses.forEach(visitor.visitStaticUse);
+ dynamicUses.forEach(visitor.visitDynamicUse);
+ typeUses.forEach(visitor.visitTypeUse);
+ }
+
String toString() => dump(this);
static String dump(WorldImpact worldImpact) {
@@ -154,6 +160,12 @@
return _staticUses != null ? _staticUses : worldImpact.staticUses;
}
+ void apply(WorldImpactVisitor visitor) {
+ staticUses.forEach(visitor.visitStaticUse);
+ dynamicUses.forEach(visitor.visitDynamicUse);
+ typeUses.forEach(visitor.visitTypeUse);
+ }
+
String toString() {
StringBuffer sb = new StringBuffer();
sb.write('TransformedWorldImpact($worldImpact)');
@@ -161,3 +173,78 @@
return sb.toString();
}
}
+
+/// Constant used to denote a specific use of a [WorldImpact].
+class ImpactUseCase {
+ final String name;
+
+ const ImpactUseCase(this.name);
+
+ String toString() => 'ImpactUseCase($name)';
+}
+
+/// Strategy used for processing [WorldImpact] object in various use cases.
+class ImpactStrategy {
+ const ImpactStrategy();
+
+ /// Applies [impact] to [visitor] for the [impactUseCase] of [element].
+ void visitImpact(Element element,
+ WorldImpact impact,
+ WorldImpactVisitor visitor,
+ ImpactUseCase impactUseCase) {
+ // Apply unconditionally.
+ impact.apply(visitor);
+ }
+
+ /// Notifies the strategy that no more impacts of [impactUseCase] will be
+ /// applied.
+ void onImpactUsed(ImpactUseCase impactUseCase) {
+ // Do nothing.
+ }
+}
+
+/// Visitor used to process the uses of a [WorldImpact].
+abstract class WorldImpactVisitor {
+ void visitStaticUse(StaticUse staticUse);
+ void visitDynamicUse(DynamicUse dynamicUse);
+ void visitTypeUse(TypeUse typeUse);
+}
+
+// TODO(johnniwinther): Remove these when we get anonymous local classes.
+typedef void VisitUse<U>(U use);
+
+class WorldImpactVisitorImpl implements WorldImpactVisitor {
+ final VisitUse<StaticUse> _visitStaticUse;
+ final VisitUse<DynamicUse> _visitDynamicUse;
+ final VisitUse<TypeUse> _visitTypeUse;
+
+ WorldImpactVisitorImpl(
+ {VisitUse<StaticUse> visitStaticUse,
+ VisitUse<DynamicUse> visitDynamicUse,
+ VisitUse<TypeUse> visitTypeUse})
+ : _visitStaticUse = visitStaticUse,
+ _visitDynamicUse = visitDynamicUse,
+ _visitTypeUse = visitTypeUse;
+
+ @override
+ void visitStaticUse(StaticUse use) {
+ if (_visitStaticUse != null) {
+ _visitStaticUse(use);
+ }
+ }
+
+ @override
+ void visitDynamicUse(DynamicUse use) {
+ if (_visitDynamicUse != null) {
+ _visitDynamicUse(use);
+ }
+ }
+
+ @override
+ void visitTypeUse(TypeUse use) {
+ if (_visitTypeUse != null) {
+ _visitTypeUse(use);
+ }
+ }
+}
+
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index b4860b8..8fd7e6c 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -675,10 +675,14 @@
return false;
}
- return element.isFinal
- || element.isConst
- || (element.isInstanceMember
- && !compiler.resolverWorld.hasInvokedSetter(element, this));
+ if (element.isFinal || element.isConst) {
+ return true;
+ }
+ if (element.isInstanceMember) {
+ return !compiler.resolverWorld.hasInvokedSetter(element, this) &&
+ !compiler.resolverWorld.fieldSetters.contains(element);
+ }
+ return false;
}
SideEffects getSideEffectsOfElement(Element element) {
diff --git a/pkg/js/README.md b/pkg/js/README.md
index 3ba66d1..e1da41e 100644
--- a/pkg/js/README.md
+++ b/pkg/js/README.md
@@ -64,7 +64,7 @@
```
If you want to use `printOptions` from Dart, you cannot simply pass a Dart `Map`
-object – they are are "opaque" in JavaScript.
+object – they are "opaque" in JavaScript.
Instead, create a Dart class with both the `@JS()` and
diff --git a/pkg/js_ast/lib/src/printer.dart b/pkg/js_ast/lib/src/printer.dart
index b2fd29d..d5c1d9b 100644
--- a/pkg/js_ast/lib/src/printer.dart
+++ b/pkg/js_ast/lib/src/printer.dart
@@ -920,6 +920,7 @@
// reserved word. We don't generate fields with reserved word names except
// for 'super'.
if (field == '"super"') return false;
+ if (field == '"catch"') return false;
return true;
}
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 8c76824..2160dd9 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -28,6 +28,7 @@
analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
[ $compiler == dart2js ]
+analyzer_cli/test/*: SkipByDesign # Only meant to run on vm
analysis_server/test/*: Skip # Issue 22161
analysis_server/test/analysis_notification_highlights_test: Pass, Slow # 19756, 21628
analysis_server/test/analysis_notification_navigation_test: Pass, Slow # Issue 19756, 21628
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index a7f3bf7..989b980 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -626,6 +626,49 @@
},
},
{
+ # dart binary for running precompiled snapshots without the compiler.
+ 'target_name': 'dart_precompiled',
+ 'type': 'executable',
+ 'dependencies': [
+ 'libdart_precompiled',
+ 'libdart_builtin',
+ 'libdart_io',
+ 'build_observatory#host',
+ 'generate_resources_cc_file#host',
+ 'generate_observatory_assets_cc_file#host',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'main.cc',
+ 'builtin_common.cc',
+ 'builtin_natives.cc',
+ 'builtin_nolib.cc',
+ 'builtin.h',
+ 'io_natives.h',
+ 'vmservice_impl.cc',
+ 'vmservice_impl.h',
+ 'snapshot_empty.cc',
+ '<(resources_cc_file)',
+ '<(observatory_assets_cc_file)',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [ '-lws2_32.lib', '-lRpcrt4.lib', '-lwinmm.lib' ],
+ },
+ # Generate an import library on Windows, by exporting a function.
+ # Extensions use this import library to link to the API in dart.exe.
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalOptions': [ '/EXPORT:Dart_True' ],
+ },
+ },
+ }],
+ ],
+ },
+ {
# dart binary built for the host. It does not use a snapshot
# and does not include Observatory.
'target_name': 'dart_bootstrap',
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index 8fcb007..054ec9b 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -16,17 +16,6 @@
'builtin_common.cc',
'dartutils.cc',
'dartutils.h',
- 'dbg_connection.cc',
- 'dbg_connection.h',
- 'dbg_connection_android.cc',
- 'dbg_connection_linux.cc',
- 'dbg_connection_linux.h',
- 'dbg_connection_macos.cc',
- 'dbg_connection_macos.h',
- 'dbg_connection_win.cc',
- 'dbg_connection_win.h',
- 'dbg_message.h',
- 'dbg_message.cc',
'directory.cc',
'directory.h',
'directory_android.cc',
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index f737132..5ba5637 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -13,6 +13,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/embedded_dart_io.h"
#include "bin/file.h"
#include "bin/io_natives.h"
#include "bin/platform.h"
@@ -90,10 +91,11 @@
if (Dart_IsError(result)) Dart_PropagateError(result);
// Uses fwrite to support printing NUL bytes.
- fwrite(chars, 1, length, stdout);
+ intptr_t res = fwrite(chars, 1, length, stdout);
+ ASSERT(res == length);
fputs("\n", stdout);
fflush(stdout);
- if (File::capture_stdout()) {
+ if (ShouldCaptureStdout()) {
// For now we report print output on the Stdout stream.
uint8_t newline[] = { '\n' };
Dart_ServiceSendDataEvent("Stdout", "WriteEvent", chars, length);
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 50ae7d0..9e2fcf7 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -34,20 +34,20 @@
namespace bin {
const char* DartUtils::original_working_directory = NULL;
-const char* DartUtils::kDartScheme = "dart:";
-const char* DartUtils::kDartExtensionScheme = "dart-ext:";
-const char* DartUtils::kAsyncLibURL = "dart:async";
-const char* DartUtils::kBuiltinLibURL = "dart:_builtin";
-const char* DartUtils::kCoreLibURL = "dart:core";
-const char* DartUtils::kInternalLibURL = "dart:_internal";
-const char* DartUtils::kIsolateLibURL = "dart:isolate";
-const char* DartUtils::kIOLibURL = "dart:io";
-const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
-const char* DartUtils::kUriLibURL = "dart:uri";
-const char* DartUtils::kHttpScheme = "http:";
-const char* DartUtils::kVMServiceLibURL = "dart:vmservice";
+const char* const DartUtils::kDartScheme = "dart:";
+const char* const DartUtils::kDartExtensionScheme = "dart-ext:";
+const char* const DartUtils::kAsyncLibURL = "dart:async";
+const char* const DartUtils::kBuiltinLibURL = "dart:_builtin";
+const char* const DartUtils::kCoreLibURL = "dart:core";
+const char* const DartUtils::kInternalLibURL = "dart:_internal";
+const char* const DartUtils::kIsolateLibURL = "dart:isolate";
+const char* const DartUtils::kIOLibURL = "dart:io";
+const char* const DartUtils::kIOLibPatchURL = "dart:io-patch";
+const char* const DartUtils::kUriLibURL = "dart:uri";
+const char* const DartUtils::kHttpScheme = "http:";
+const char* const DartUtils::kVMServiceLibURL = "dart:vmservice";
-uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
+const uint8_t DartUtils::magic_number[] = { 0xf5, 0xf5, 0xdc, 0xdc };
static bool IsWindowsHost() {
#if defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index cd3ce0e..2c497b2 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -216,20 +216,20 @@
// Global state that stores the original working directory..
static const char* original_working_directory;
- static const char* kDartScheme;
- static const char* kDartExtensionScheme;
- static const char* kAsyncLibURL;
- static const char* kBuiltinLibURL;
- static const char* kCoreLibURL;
- static const char* kInternalLibURL;
- static const char* kIsolateLibURL;
- static const char* kIOLibURL;
- static const char* kIOLibPatchURL;
- static const char* kUriLibURL;
- static const char* kHttpScheme;
- static const char* kVMServiceLibURL;
+ static const char* const kDartScheme;
+ static const char* const kDartExtensionScheme;
+ static const char* const kAsyncLibURL;
+ static const char* const kBuiltinLibURL;
+ static const char* const kCoreLibURL;
+ static const char* const kInternalLibURL;
+ static const char* const kIsolateLibURL;
+ static const char* const kIOLibURL;
+ static const char* const kIOLibPatchURL;
+ static const char* const kUriLibURL;
+ static const char* const kHttpScheme;
+ static const char* const kVMServiceLibURL;
- static uint8_t magic_number[];
+ static const uint8_t magic_number[];
private:
DISALLOW_ALLOCATION();
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
deleted file mode 100644
index 6bd0cda..0000000
--- a/runtime/bin/dbg_connection.cc
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/dbg_connection.h"
-#include "bin/dbg_message.h"
-#include "bin/dartutils.h"
-#include "bin/lockers.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "platform/utils.h"
-
-#include "include/dart_api.h"
-
-
-namespace dart {
-namespace bin {
-
-bool trace_debug_protocol = false;
-
-intptr_t DebuggerConnectionHandler::listener_fd_ = -1;
-Monitor* DebuggerConnectionHandler::handler_lock_ = new Monitor();
-
-// TODO(asiva): Remove this once we have support for multiple debugger
-// connections. For now we just store the single debugger connection
-// handler in a static variable.
-static DebuggerConnectionHandler* singleton_handler = NULL;
-
-// The maximum message length to print when --trace_debug_protocol is
-// specified.
-static const int kMaxPrintMessageLen = 1024;
-
-class MessageBuffer {
- public:
- explicit MessageBuffer(intptr_t fd);
- ~MessageBuffer();
- void ReadData();
- bool IsValidMessage() const;
- void PopMessage();
- int MessageId() const;
- char* buf() const { return buf_; }
- bool Alive() const { return connection_is_alive_; }
-
- private:
- static const int kInitialBufferSize = 256;
- char* buf_;
- int buf_length_;
- intptr_t fd_;
- int data_length_;
- bool connection_is_alive_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
-};
-
-
-MessageBuffer::MessageBuffer(intptr_t fd)
- : buf_(NULL),
- buf_length_(0),
- fd_(fd),
- data_length_(0),
- connection_is_alive_(true) {
- buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
- if (buf_ == NULL) {
- FATAL("Failed to allocate message buffer\n");
- }
- buf_length_ = kInitialBufferSize;
- buf_[0] = '\0';
- data_length_ = 0;
-}
-
-
-MessageBuffer::~MessageBuffer() {
- free(buf_);
- buf_ = NULL;
- fd_ = -1;
-}
-
-
-bool MessageBuffer::IsValidMessage() const {
- if (data_length_ == 0) {
- return false;
- }
- dart::JSONReader msg_reader(buf_);
- return msg_reader.EndOfObject() != NULL;
-}
-
-
-int MessageBuffer::MessageId() const {
- dart::JSONReader r(buf_);
- r.Seek("id");
- if (r.Type() == dart::JSONReader::kInteger) {
- return atoi(r.ValueChars());
- } else {
- return -1;
- }
-}
-
-
-void MessageBuffer::ReadData() {
- ASSERT(data_length_ >= 0);
- ASSERT(data_length_ < buf_length_);
- int max_read = buf_length_ - data_length_ - 1;
- if (max_read == 0) {
- // TODO(hausner):
- // Buffer is full. What should we do if there is no valid message
- // in the buffer? This might be possible if the client sends a message
- // that's larger than the buffer, of if the client sends malformed
- // messages that keep piling up.
- ASSERT(IsValidMessage());
- return;
- }
- // TODO(hausner): Handle error conditions returned by Read. We may
- // want to close the debugger connection if we get any errors.
- int bytes_read =
- DebuggerConnectionImpl::Receive(fd_, buf_ + data_length_, max_read);
- if (bytes_read == 0) {
- connection_is_alive_ = false;
- return;
- }
- ASSERT(bytes_read > 0);
- data_length_ += bytes_read;
- ASSERT(data_length_ < buf_length_);
- buf_[data_length_] = '\0';
-}
-
-
-void MessageBuffer::PopMessage() {
- dart::JSONReader msg_reader(buf_);
- const char* end = msg_reader.EndOfObject();
- if (end != NULL) {
- ASSERT(*end == '}');
- end++;
- data_length_ = 0;
- while (*end != '\0') {
- buf_[data_length_] = *end++;
- data_length_++;
- }
- buf_[data_length_] = '\0';
- ASSERT(data_length_ < buf_length_);
- }
-}
-
-
-static bool IsValidJSON(const char* msg) {
- dart::JSONReader r(msg);
- return r.CheckMessage();
-}
-
-
-DebuggerConnectionHandler::DebuggerConnectionHandler(intptr_t debug_fd)
- : debug_fd_(debug_fd), msgbuf_(NULL) {
- msgbuf_ = new MessageBuffer(debug_fd_);
-}
-
-
-DebuggerConnectionHandler::~DebuggerConnectionHandler() {
- CloseDbgConnection();
- DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
-}
-
-
-int DebuggerConnectionHandler::MessageId() {
- ASSERT(msgbuf_ != NULL);
- return msgbuf_->MessageId();
-}
-
-
-void DebuggerConnectionHandler::HandleUnknownMsg() {
- int msg_id = msgbuf_->MessageId();
- ASSERT(msg_id >= 0);
- SendError(debug_fd_, msg_id, "unknown debugger command");
-}
-
-
-typedef void (*CommandHandler)(DbgMessage* msg);
-
-struct JSONDebuggerCommand {
- const char* cmd_string;
- CommandHandler handler_function;
-};
-
-
-void DebuggerConnectionHandler::HandleMessages() {
- static JSONDebuggerCommand generic_debugger_commands[] = {
- { "interrupt", HandleInterruptCmd },
- { "getIsolateIds", HandleIsolatesListCmd },
- { NULL, NULL }
- };
-
- for (;;) {
- // Read a message.
- while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
- msgbuf_->ReadData();
- }
- if (!msgbuf_->Alive()) {
- if (trace_debug_protocol) {
- Log::Print("Debugger is exiting HandleMessages loop.\n");
- }
- return;
- }
-
- if (trace_debug_protocol) {
- dart::JSONReader r(msgbuf_->buf());
- const char* msg_end = r.EndOfObject();
- if (msg_end != NULL) {
- intptr_t msg_len = msg_end - msgbuf_->buf();
- int print_len = ((msg_len > kMaxPrintMessageLen)
- ? kMaxPrintMessageLen : msg_len);
- Log::Print("[<<<] Receiving message from debug fd %" Pd ":\n%.*s%s\n",
- debug_fd_, print_len, msgbuf_->buf(),
- ((msg_len > print_len) ? "..." : ""));
- }
- }
-
- // Parse out the command portion from the message.
- dart::JSONReader r(msgbuf_->buf());
- bool found = r.Seek("command");
- if (r.Error()) {
- FATAL("Illegal JSON message received");
- }
- if (!found) {
- Log::Print("'command' not found in JSON message: '%s'\n",
- msgbuf_->buf());
- msgbuf_->PopMessage();
- }
-
- // Check if this is a generic command (not isolate specific).
- int i = 0;
- bool is_handled = false;
- while (generic_debugger_commands[i].cmd_string != NULL) {
- if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
- DbgMessage* msg = new DbgMessage(i,
- msgbuf_->buf(),
- r.EndOfObject(),
- debug_fd_);
- (*generic_debugger_commands[i].handler_function)(msg);
- is_handled = true;
- msgbuf_->PopMessage();
- delete msg;
- break;
- }
- i++;
- }
- if (!is_handled) {
- // Check if this is an isolate specific command.
- int32_t cmd_idx = DbgMsgQueueList::LookupIsolateCommand(r.ValueChars(),
- r.ValueLen());
- if (cmd_idx != DbgMsgQueueList::kInvalidCommand) {
- const char* start = msgbuf_->buf();
- const char* end = r.EndOfObject();
- // Get debug message queue corresponding to isolate.
- MessageParser msg_parser(start, (end - start));
- Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
- if (!DbgMsgQueueList::AddIsolateMessage(isolate_id,
- cmd_idx,
- msgbuf_->buf(),
- r.EndOfObject(),
- debug_fd_)) {
- SendError(debug_fd_, MessageId(), "Invalid isolate specified");
- }
- msgbuf_->PopMessage();
- continue;
- }
-
- // This is an unrecognized command, report error and move on to next.
- Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
- HandleUnknownMsg();
- msgbuf_->PopMessage();
- }
- }
-}
-
-
-void DebuggerConnectionHandler::SendError(intptr_t debug_fd,
- int msg_id,
- const char* err_msg) {
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
- msg.AddEscapedString(err_msg);
- msg.Printf("\"}");
- SendMsg(debug_fd, &msg);
-}
-
-
-void DebuggerConnectionHandler::CloseDbgConnection() {
- if (debug_fd_ >= 0) {
- Socket::Close(debug_fd_);
- }
- if (msgbuf_ != NULL) {
- delete msgbuf_;
- msgbuf_ = NULL;
- }
- // TODO(hausner): Need to tell the VM debugger object to remove all
- // breakpoints.
-}
-
-
-// The vm service relies on certain debugger functionality.
-void DebuggerConnectionHandler::InitForVmService() {
- MonitorLocker ml(handler_lock_);
- DbgMsgQueueList::Initialize();
-}
-
-
-int DebuggerConnectionHandler::StartHandler(const char* address,
- int port_number) {
- ASSERT(handler_lock_ != NULL);
- MonitorLocker ml(handler_lock_);
- if (IsListening()) {
- // The debugger connection handler was already started.
- return Socket::GetPort(listener_fd_);
- }
-
- // First setup breakpoint, exception and delayed breakpoint handlers.
- DbgMsgQueueList::Initialize();
-
- // Initialize the socket implementation.
- if (!Socket::Initialize()) {
- FATAL("Failed initializing socket implementation.");
- }
-
- // Now setup a listener socket and start a thread which will
- // listen, accept connections from debuggers, read and handle/dispatch
- // debugger commands received on these connections.
- ASSERT(listener_fd_ == -1);
- OSError *os_error;
- AddressList<SocketAddress>* addresses =
- Socket::LookupAddress(address, -1, &os_error);
- RawAddr addr = addresses->GetAt(0)->addr();
- SocketAddress::SetAddrPort(&addr, port_number);
- listener_fd_ = ServerSocket::CreateBindListen(addr, 1);
- delete addresses;
- if (listener_fd_ < 0) {
- fprintf(stderr, "%s", "Could not initialize debug socket\n");
- fflush(stderr);
- exit(255);
- }
-
- port_number = Socket::GetPort(listener_fd_);
- DebuggerConnectionImpl::StartHandler(port_number);
- return port_number;
-}
-
-
-void DebuggerConnectionHandler::StopHandler() {
- if (IsConnected()) {
- DebuggerConnectionImpl::StopHandler(singleton_handler->debug_fd());
- }
-}
-
-
-void DebuggerConnectionHandler::WaitForConnection() {
- ASSERT(handler_lock_ != NULL);
- MonitorLocker ml(handler_lock_);
- if (!IsListening()) {
- // If we are only running the vm service, don't wait for
- // connections.
- return;
- }
- while (!IsConnected()) {
- Monitor::WaitResult res = ml.Wait();
- ASSERT(res == Monitor::kNotified);
- }
-}
-
-
-void DebuggerConnectionHandler::SendMsg(intptr_t debug_fd,
- dart::TextBuffer* msg) {
- ASSERT(handler_lock_ != NULL);
- MonitorLocker ml(handler_lock_);
- SendMsgHelper(debug_fd, msg);
-}
-
-
-void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
- ASSERT(handler_lock_ != NULL);
- MonitorLocker ml(handler_lock_);
- if (!IsListening()) {
- // If we are only running the vm service, don't try to broadcast
- // to debugger clients.
- return;
- }
- // TODO(asiva): Once we support connection to multiple debuggers
- // we need to send the message to all of them.
- ASSERT(singleton_handler != NULL);
- SendMsgHelper(singleton_handler->debug_fd(), msg);
-}
-
-
-void DebuggerConnectionHandler::SendMsgHelper(intptr_t debug_fd,
- dart::TextBuffer* msg) {
- ASSERT(debug_fd >= 0);
- ASSERT(IsValidJSON(msg->buf()));
-
- if (trace_debug_protocol) {
- int print_len = ((msg->length() > kMaxPrintMessageLen)
- ? kMaxPrintMessageLen : msg->length());
- Log::Print("[>>>] Sending message to debug fd %" Pd ":\n%.*s%s\n",
- debug_fd, print_len, msg->buf(),
- ((msg->length() > print_len) ? "..." : ""));
- }
-
- // Sending messages in short pieces can be used to stress test the
- // debugger front-end's message handling code.
- const bool send_in_pieces = false;
- if (send_in_pieces) {
- intptr_t remaining = msg->length();
- intptr_t sent = 0;
- const intptr_t max_piece_len = 122; // Pretty arbitrary, not a power of 2.
- Monitor sleep;
- while (remaining > 0) {
- intptr_t piece_len = remaining;
- if (piece_len > max_piece_len) {
- piece_len = max_piece_len;
- }
- intptr_t written =
- DebuggerConnectionImpl::Send(debug_fd, msg->buf() + sent, piece_len);
- ASSERT(written == piece_len);
- sent += written;
- remaining -= written;
- // Wait briefly so the OS does not coalesce message fragments.
- {
- MonitorLocker ml(&sleep);
- ml.Wait(10);
- }
- }
- return;
- }
- intptr_t bytes_written =
- DebuggerConnectionImpl::Send(debug_fd, msg->buf(), msg->length());
- ASSERT(msg->length() == bytes_written);
- // TODO(hausner): Error checking. Probably just shut down the debugger
- // session if we there is an error while writing.
-}
-
-
-void DebuggerConnectionHandler::AcceptDbgConnection(intptr_t debug_fd) {
- Socket::SetNoDelay(debug_fd, true);
- AddNewDebuggerConnection(debug_fd);
- {
- ASSERT(handler_lock_ != NULL);
- MonitorLocker ml(handler_lock_);
- ml.NotifyAll();
- }
- // TODO(asiva): Once we implement support for multiple connections
- // we should have a different callback for wakeups on fds which
- // are not the listener_fd_.
- // In that callback we would lookup the handler object
- // corresponding to that fd and invoke HandleMessages on it.
- // For now we run that code here.
- DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
- if (handler != NULL) {
- handler->HandleMessages();
- delete handler;
- }
-}
-
-
-void DebuggerConnectionHandler::HandleInterruptCmd(DbgMessage* in_msg) {
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
- if (isolate_id == ILLEGAL_ISOLATE_ID || Dart_GetIsolate(isolate_id) == NULL) {
- in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
- return;
- }
- if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
- in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
- return;
- }
- dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d }", msg_id);
- in_msg->SendReply(&msg);
-}
-
-
-void DebuggerConnectionHandler::HandleIsolatesListCmd(DbgMessage* in_msg) {
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- ASSERT(msg_id >= 0);
- dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
- DbgMsgQueueList::ListIsolateIds(&msg);
- msg.Printf("]}}");
- in_msg->SendReply(&msg);
-}
-
-
-void DebuggerConnectionHandler::AddNewDebuggerConnection(intptr_t debug_fd) {
- // TODO(asiva): Support multiple debugger connections, for now we just
- // create one handler, store it in a static variable and use it.
- ASSERT(singleton_handler == NULL);
- singleton_handler = new DebuggerConnectionHandler(debug_fd);
-}
-
-
-void DebuggerConnectionHandler::RemoveDebuggerConnection(intptr_t debug_fd) {
- // TODO(asiva): Support multiple debugger connections, for now we just
- // set the static handler back to NULL.
- ASSERT(singleton_handler != NULL);
- singleton_handler = NULL;
-}
-
-
-DebuggerConnectionHandler*
-DebuggerConnectionHandler::GetDebuggerConnectionHandler(intptr_t debug_fd) {
- // TODO(asiva): Support multiple debugger connections, for now we just
- // return the one static handler that was created.
- ASSERT(singleton_handler != NULL);
- return singleton_handler;
-}
-
-
-bool DebuggerConnectionHandler::IsConnected() {
- // TODO(asiva): Support multiple debugger connections.
- // Return true if a connection has been established.
- return singleton_handler != NULL;
-}
-
-} // namespace bin
-} // namespace dart
diff --git a/runtime/bin/dbg_connection.h b/runtime/bin/dbg_connection.h
deleted file mode 100644
index 577c30a..0000000
--- a/runtime/bin/dbg_connection.h
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_H_
-#define BIN_DBG_CONNECTION_H_
-
-#include "bin/builtin.h"
-#include "bin/utils.h"
-
-#include "include/dart_tools_api.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "bin/thread.h"
-// Declare the OS-specific types ahead of defining the generic class.
-#if defined(TARGET_OS_ANDROID)
-#include "bin/dbg_connection_android.h"
-#elif defined(TARGET_OS_LINUX)
-#include "bin/dbg_connection_linux.h"
-#elif defined(TARGET_OS_MACOS)
-#include "bin/dbg_connection_macos.h"
-#elif defined(TARGET_OS_WINDOWS)
-#include "bin/dbg_connection_win.h"
-#else
-#error Unknown target os.
-#endif
-
-
-namespace dart {
-namespace bin {
-
-// Forward declarations.
-class DbgMessage;
-class MessageBuffer;
-
-
-class DebuggerConnectionHandler {
- public:
- explicit DebuggerConnectionHandler(intptr_t debug_fd);
- ~DebuggerConnectionHandler();
-
- // Accessors.
- intptr_t debug_fd() const { return debug_fd_; }
-
- // Return message id of current debug command message.
- int MessageId();
-
- // Starts the native thread which listens for connections from
- // debugger clients, reads and dispatches debug command messages
- // from the client.
- static int StartHandler(const char* address, int port_number);
-
- // Stops the native thread.
- static void StopHandler();
-
- // Initializes the parts of the debugger which are needed by the vm
- // service. This function should only be called when StartHandler
- // is not called.
- static void InitForVmService();
-
- // Called by Isolates when they need to wait for a connection
- // from debugger clients.
- static void WaitForConnection();
-
- // Sends a reply or an error message to a specific debugger client.
- static void SendMsg(intptr_t debug_fd, dart::TextBuffer* msg);
- static void SendError(intptr_t debug_fd, int msg_id, const char* err_msg);
-
- // Sends an event message to all debugger clients that are connected.
- static void BroadcastMsg(dart::TextBuffer* msg);
-
- private:
- void HandleUnknownMsg();
- void HandleMessages();
-
- void CloseDbgConnection();
-
- // The socket that connects with the debugger client.
- // The descriptor is created and closed by the debugger connection thread.
- intptr_t debug_fd_;
-
- // Buffer holding the messages received over the wire from the debugger
- // front end..
- MessageBuffer* msgbuf_;
-
- // Accepts connection requests from debugger client and sets up a
- // connection handler object to read and handle messages from the client.
- static void AcceptDbgConnection(intptr_t debug_fd);
-
- // Handlers for generic debug command messages which are not specific to
- // an isolate.
- static void HandleInterruptCmd(DbgMessage* msg);
- static void HandleIsolatesListCmd(DbgMessage* msg);
-
- // Helper methods to manage debugger client connections.
- static void AddNewDebuggerConnection(intptr_t debug_fd);
- static void RemoveDebuggerConnection(intptr_t debug_fd);
- static DebuggerConnectionHandler* GetDebuggerConnectionHandler(
- intptr_t debug_fd);
- static bool IsConnected();
-
- // Helper method for sending messages back to a debugger client.
- static void SendMsgHelper(intptr_t debug_fd, dart::TextBuffer* msg);
-
- // mutex/condition variable used by isolates when writing back to the
- // debugger. This is also used to ensure that the isolate waits for
- // a debugger to be attached when that is requested on the command line.
- static Monitor* handler_lock_;
-
- static bool IsListening() {
- return listener_fd_ != -1;
- }
-
- // The socket that is listening for incoming debugger connections.
- // This descriptor is created and closed by a native thread.
- static intptr_t listener_fd_;
-
- friend class DebuggerConnectionImpl;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DebuggerConnectionHandler);
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_CONNECTION_H_
diff --git a/runtime/bin/dbg_connection_android.cc b/runtime/bin/dbg_connection_android.cc
deleted file mode 100644
index 77c7a20..0000000
--- a/runtime/bin/dbg_connection_android.cc
+++ /dev/null
@@ -1,131 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_ANDROID)
-
-#include <errno.h> // NOLINT
-#include <stdio.h> // NOLINT
-#include <stdlib.h> // NOLINT
-#include <sys/epoll.h> // NOLINT
-
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-
-#include "platform/signal_blocker.h"
-
-
-namespace dart {
-namespace bin {
-
-intptr_t DebuggerConnectionImpl::epoll_fd_ = -1;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
-
-
-void DebuggerConnectionImpl::HandleEvent(struct epoll_event* event) {
- if (event->data.fd == DebuggerConnectionHandler::listener_fd_) {
- if (DebuggerConnectionHandler::IsConnected()) {
- FATAL("Cannot connect to more than one debugger.\n");
- }
- intptr_t fd = ServerSocket::Accept(event->data.fd);
- if (fd < 0) {
- FATAL("Accepting new debugger connection failed.\n");
- }
- FDUtils::SetBlocking(fd);
- DebuggerConnectionHandler::AcceptDbgConnection(fd);
- // TODO(hausner): add the debugger wire socket fd to the event poll queue
- // once we poll the debugger connection.
- } else if (event->data.fd == wakeup_fds_[0]) {
- // Sync message. Not yet implemented.
- UNIMPLEMENTED();
- } else {
- Log::Print("unexpected: receiving debugger connection event.\n");
- UNIMPLEMENTED();
- }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
- static const int kMaxEvents = 4;
- struct epoll_event events[kMaxEvents];
- while (1) {
- const int no_timeout = -1;
- intptr_t result = TEMP_FAILURE_RETRY(
- epoll_wait(epoll_fd_, events, kMaxEvents, no_timeout));
- ASSERT(EAGAIN == EWOULDBLOCK);
- if (result == -1) {
- if (errno != EWOULDBLOCK) {
- perror("epoll_wait failed");
- }
- } else {
- ASSERT(result <= kMaxEvents);
- for (int i = 0; i < result; i++) {
- HandleEvent(&events[i]);
- }
- }
- }
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
- int result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
- if (result != 0) {
- FATAL1("Pipe creation failed with error %d\n", result);
- }
- FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
- static const int kEpollInitialSize = 16;
- epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
- if (epoll_fd_ == -1) {
- FATAL("Failed creating epoll file descriptor");
- }
-
- // Register the wakeup _fd with the epoll instance.
- struct epoll_event event;
- event.events = EPOLLIN;
- event.data.fd = wakeup_fds_[0];
- int status = NO_RETRY_EXPECTED(epoll_ctl(
- epoll_fd_, EPOLL_CTL_ADD, wakeup_fds_[0], &event));
- if (status == -1) {
- FATAL("Failed adding wakeup fd to epoll instance");
- }
-
- // Register the listener_fd with the epoll instance.
- event.events = EPOLLIN;
- event.data.fd = DebuggerConnectionHandler::listener_fd_;
- status = NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD,
- DebuggerConnectionHandler::listener_fd_, &event));
- if (status == -1) {
- FATAL("Failed adding listener fd to epoll instance");
- }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
- ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
- SetupPollQueue();
- int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
- if (result != 0) {
- FATAL1("Failed to start debugger connection handler thread: %d\n", result);
- }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
- const char* buf,
- int len) {
- return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
- return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-} // namespace bin
-} // namespace dart
-
-#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/bin/dbg_connection_android.h b/runtime/bin/dbg_connection_android.h
deleted file mode 100644
index 8975294..0000000
--- a/runtime/bin/dbg_connection_android.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_ANDROID_H_
-#define BIN_DBG_CONNECTION_ANDROID_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
- static void StartHandler(int port_number);
- static void StopHandler(intptr_t debug_fd) {}
- static intptr_t Send(intptr_t socket, const char* buf, int len);
- static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
- static void SetupPollQueue();
- static void HandleEvent(struct epoll_event* event);
- static void Handler(uword args);
-
- // File descriptors for pipes used to communicate with the debugger thread.
- static int wakeup_fds_[2];
-
- // File descriptor for the polling queue.
- static intptr_t epoll_fd_;
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_CONNECTION_ANDROID_H_
diff --git a/runtime/bin/dbg_connection_linux.cc b/runtime/bin/dbg_connection_linux.cc
deleted file mode 100644
index a55557d..0000000
--- a/runtime/bin/dbg_connection_linux.cc
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_LINUX)
-
-#include <errno.h> // NOLINT
-#include <stdio.h> // NOLINT
-#include <stdlib.h> // NOLINT
-#include <sys/epoll.h> // NOLINT
-
-#include "platform/signal_blocker.h"
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-
-
-namespace dart {
-namespace bin {
-
-int DebuggerConnectionImpl::epoll_fd_ = -1;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {-1, -1};
-
-
-void DebuggerConnectionImpl::HandleEvent(struct epoll_event* event) {
- if (event->data.fd == DebuggerConnectionHandler::listener_fd_) {
- if (DebuggerConnectionHandler::IsConnected()) {
- FATAL("Cannot connect to more than one debugger.\n");
- }
- intptr_t fd = ServerSocket::Accept(event->data.fd);
- if (fd < 0) {
- FATAL("Accepting new debugger connection failed.\n");
- }
- FDUtils::SetBlocking(fd);
- DebuggerConnectionHandler::AcceptDbgConnection(fd);
- // TODO(hausner): add the debugger wire socket fd to the event poll queue
- // once we poll the debugger connection.
- } else if (event->data.fd == wakeup_fds_[0]) {
- // Sync message. Not yet implemented.
- UNIMPLEMENTED();
- } else {
- Log::Print("unexpected: receiving debugger connection event.\n");
- UNIMPLEMENTED();
- }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
- static const int kMaxEvents = 4;
- struct epoll_event events[kMaxEvents];
- while (1) {
- const int no_timeout = -1;
- intptr_t result = TEMP_FAILURE_RETRY(
- epoll_wait(epoll_fd_, events, kMaxEvents, no_timeout));
- ASSERT(EAGAIN == EWOULDBLOCK);
- if (result == -1) {
- if (errno != EWOULDBLOCK) {
- perror("epoll_wait failed");
- }
- } else {
- ASSERT(result <= kMaxEvents);
- for (int i = 0; i < result; i++) {
- HandleEvent(&events[i]);
- }
- }
- }
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
- int result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
- if (result != 0) {
- FATAL1("Pipe creation failed with error %d\n", result);
- }
- FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
- static const int kEpollInitialSize = 16;
- epoll_fd_ = NO_RETRY_EXPECTED(epoll_create(kEpollInitialSize));
- if (epoll_fd_ == -1) {
- FATAL("Failed creating epoll file descriptor");
- }
-
- // Register the wakeup _fd with the epoll instance.
- struct epoll_event event;
- event.events = EPOLLIN;
- event.data.fd = wakeup_fds_[0];
- int status = NO_RETRY_EXPECTED(epoll_ctl(
- epoll_fd_, EPOLL_CTL_ADD, wakeup_fds_[0], &event));
- if (status == -1) {
- FATAL("Failed adding wakeup fd to epoll instance");
- }
-
- // Register the listener_fd with the epoll instance.
- event.events = EPOLLIN;
- event.data.fd = DebuggerConnectionHandler::listener_fd_;
- status = NO_RETRY_EXPECTED(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD,
- DebuggerConnectionHandler::listener_fd_, &event));
- if (status == -1) {
- FATAL("Failed adding listener fd to epoll instance");
- }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
- ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
- SetupPollQueue();
- int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
- if (result != 0) {
- FATAL1("Failed to start debugger connection handler thread: %d\n", result);
- }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
- const char* buf,
- int len) {
- return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
- return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-} // namespace bin
-} // namespace dart
-
-#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/dbg_connection_linux.h b/runtime/bin/dbg_connection_linux.h
deleted file mode 100644
index fcbd16e..0000000
--- a/runtime/bin/dbg_connection_linux.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_LINUX_H_
-#define BIN_DBG_CONNECTION_LINUX_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
- static void StartHandler(int port_number);
- static void StopHandler(intptr_t debug_fd) {}
- static intptr_t Send(intptr_t socket, const char* buf, int len);
- static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
- static void SetupPollQueue();
- static void HandleEvent(struct epoll_event* event);
- static void Handler(uword args);
-
- // File descriptors for pipes used to communicate with the debugger thread.
- static int wakeup_fds_[2];
-
- // File descriptor for the polling queue.
- static int epoll_fd_;
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_CONNECTION_LINUX_H_
diff --git a/runtime/bin/dbg_connection_macos.cc b/runtime/bin/dbg_connection_macos.cc
deleted file mode 100644
index 4da21cd..0000000
--- a/runtime/bin/dbg_connection_macos.cc
+++ /dev/null
@@ -1,193 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_MACOS)
-
-#include <errno.h> // NOLINT
-#include <stdio.h> // NOLINT
-#include <stdlib.h> // NOLINT
-#include <string.h> // NOLINT
-#include <sys/event.h> // NOLINT
-#include <unistd.h> // NOLINT
-
-#include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
-#include "bin/fdutils.h"
-#include "bin/log.h"
-#include "bin/socket.h"
-#include "platform/signal_blocker.h"
-#include "platform/utils.h"
-
-
-namespace dart {
-namespace bin {
-
-#define INVALID_FD -1
-
-int DebuggerConnectionImpl::kqueue_fd_ = INVALID_FD;
-int DebuggerConnectionImpl::wakeup_fds_[2] = {INVALID_FD, INVALID_FD};
-
-
-// Used by VM threads to send a message to the debugger connetion
-// handler thread.
-void DebuggerConnectionImpl::SendMessage(MessageType id) {
- ASSERT(wakeup_fds_[1] != INVALID_FD);
- struct Message msg;
- msg.msg_id = id;
- int result = FDUtils::WriteToBlocking(wakeup_fds_[1], &msg, sizeof(msg));
- if (result != sizeof(msg)) {
- if (result == -1) {
- perror("Wakeup message failure: ");
- }
- FATAL1("Wakeup message failure. Wrote %d bytes.", result);
- }
-}
-
-
-// Used by the debugger connection handler to read the messages sent
-// by the VM.
-bool DebuggerConnectionImpl::ReceiveMessage(Message* msg) {
- int total_read = 0;
- int bytes_read = 0;
- int remaining = sizeof(Message);
- uint8_t* buf = reinterpret_cast<uint8_t*>(msg);
- while (remaining > 0) {
- bytes_read =
- TEMP_FAILURE_RETRY(read(wakeup_fds_[0], buf + total_read, remaining));
- if ((bytes_read < 0) && (total_read == 0)) {
- return false;
- }
- if (bytes_read > 0) {
- total_read += bytes_read;
- remaining -= bytes_read;
- }
- }
- ASSERT(remaining >= 0);
- return remaining == 0;
-}
-
-
-void DebuggerConnectionImpl::HandleEvent(struct kevent* event) {
- intptr_t ident = event->ident;
- if (ident == DebuggerConnectionHandler::listener_fd_) {
- if (DebuggerConnectionHandler::IsConnected()) {
- FATAL("Cannot connect to more than one debugger.\n");
- }
- intptr_t fd = ServerSocket::Accept(ident);
- if (fd < 0) {
- FATAL("Accepting new debugger connection failed.\n");
- }
- FDUtils::SetBlocking(fd);
- DebuggerConnectionHandler::AcceptDbgConnection(fd);
-
- /* For now, don't poll the debugger connection.
- struct kevent ev_add;
- EV_SET(&ev_add, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
- int status =
- TEMP_FAILURE_RETRY(kevent(kqueue_fd_, &ev_add, 1, NULL, 0, NULL));
- if (status == -1) {
- const int kBufferSize = 1024;
- char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
- FATAL1("Failed adding debugger socket to kqueue: %s\n", error_message);
- }
- */
- } else if (ident == wakeup_fds_[0]) {
- Message msg;
- if (ReceiveMessage(&msg)) {
- Log::Print("Received sync message id %d.\n", msg.msg_id);
- }
- } else {
- Log::Print("unexpected: receiving debugger connection event.\n");
- UNIMPLEMENTED();
- }
-}
-
-
-void DebuggerConnectionImpl::Handler(uword args) {
- static const int kMaxEvents = 4;
- struct kevent events[kMaxEvents];
-
- while (1) {
- // Wait indefinitely for an event.
- int result = TEMP_FAILURE_RETRY(
- kevent(kqueue_fd_, NULL, 0, events, kMaxEvents, NULL));
- if (result == -1) {
- const int kBufferSize = 1024;
- char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
- FATAL1("kevent failed %s\n", error_message);
- } else {
- ASSERT(result <= kMaxEvents);
- for (int i = 0; i < result; i++) {
- HandleEvent(&events[i]);
- }
- }
- }
- Log::Print("shutting down debugger thread\n");
-}
-
-
-void DebuggerConnectionImpl::SetupPollQueue() {
- int result;
- result = NO_RETRY_EXPECTED(pipe(wakeup_fds_));
- if (result != 0) {
- FATAL1("Pipe creation failed with error %d\n", result);
- }
- FDUtils::SetNonBlocking(wakeup_fds_[0]);
-
- kqueue_fd_ = NO_RETRY_EXPECTED(kqueue());
- if (kqueue_fd_ == -1) {
- FATAL("Failed creating kqueue\n");
- }
- // Register the wakeup_fd_ with the kqueue.
- struct kevent event;
- EV_SET(&event, wakeup_fds_[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
- int status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
- if (status == -1) {
- const int kBufferSize = 1024;
- char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
- FATAL1("Failed adding wakeup pipe fd to kqueue: %s\n", error_message);
- }
-
- // Register the listening socket.
- EV_SET(&event, DebuggerConnectionHandler::listener_fd_,
- EVFILT_READ, EV_ADD, 0, 0, NULL);
- status = NO_RETRY_EXPECTED(kevent(kqueue_fd_, &event, 1, NULL, 0, NULL));
- if (status == -1) {
- const int kBufferSize = 1024;
- char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
- FATAL1("Failed adding listener socket to kqueue: %s\n", error_message);
- }
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
- ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
- SetupPollQueue();
- int result = Thread::Start(&DebuggerConnectionImpl::Handler, 0);
- if (result != 0) {
- FATAL1("Failed to start debugger connection handler thread: %d\n", result);
- }
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
- const char* buf,
- int len) {
- return TEMP_FAILURE_RETRY(write(socket, buf, len));
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
- return TEMP_FAILURE_RETRY(read(socket, buf, len));
-}
-
-} // namespace bin
-} // namespace dart
-
-#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/dbg_connection_macos.h b/runtime/bin/dbg_connection_macos.h
deleted file mode 100644
index 064238e..0000000
--- a/runtime/bin/dbg_connection_macos.h
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_MACOS_H_
-#define BIN_DBG_CONNECTION_MACOS_H_
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
- static void StartHandler(int port_number);
- static void StopHandler(intptr_t debug_fd) {}
- static intptr_t Send(intptr_t socket, const char* buf, int len);
- static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
- enum MessageType {
- kAddDbgFd = 1,
- kRemoveDbgFd,
- kQuit
- };
-
- struct Message {
- MessageType msg_id;
- };
-
- static void SendMessage(MessageType id);
- static bool ReceiveMessage(Message* msg);
-
- static void SetupPollQueue();
- static void HandleEvent(struct kevent* event);
- static void Handler(uword args);
-
-
-
- // File descriptors for pipes used to communicate with the debugger thread.
- static int wakeup_fds_[2];
- // File descriptor for the polling queue.
- static int kqueue_fd_;
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_CONNECTION_MACOS_H_
diff --git a/runtime/bin/dbg_connection_win.cc b/runtime/bin/dbg_connection_win.cc
deleted file mode 100644
index 49bc4a9..0000000
--- a/runtime/bin/dbg_connection_win.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_WINDOWS)
-
-#include "bin/dbg_connection.h"
-
-#include "bin/eventhandler.h"
-#include "bin/lockers.h"
-#include "bin/log.h"
-#include "bin/thread.h"
-
-namespace dart {
-namespace bin {
-
-Monitor* DebuggerConnectionImpl::handler_monitor_ = new Monitor();
-ThreadId DebuggerConnectionImpl::handler_thread_id_ = Thread::kInvalidThreadId;
-bool DebuggerConnectionImpl::handler_thread_running_ = false;
-
-
-void DebuggerConnectionImpl::NotifyThreadStarted() {
- MonitorLocker ml(handler_monitor_);
- ASSERT(!handler_thread_running_);
- ASSERT(handler_thread_id_ == Thread::kInvalidThreadId);
- handler_thread_running_ = true;
- handler_thread_id_ = Thread::GetCurrentThreadId();
- ml.Notify();
-}
-
-
-void DebuggerConnectionImpl::WaitForThreadStarted() {
- MonitorLocker ml(handler_monitor_);
- while (!handler_thread_running_) {
- ml.Wait();
- }
- ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
-}
-
-
-void DebuggerConnectionImpl::NotifyThreadFinished() {
- MonitorLocker ml(handler_monitor_);
- ASSERT(handler_thread_running_);
- ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
- handler_thread_running_ = false;
- ml.Notify();
-}
-
-
-void DebuggerConnectionImpl::WaitForThreadFinished() {
- MonitorLocker ml(handler_monitor_);
- while (handler_thread_running_) {
- ml.Wait();
- }
- ASSERT(handler_thread_id_ != Thread::kInvalidThreadId);
- Thread::Join(handler_thread_id_);
- handler_thread_id_ = Thread::kInvalidThreadId;
-}
-
-
-void DebuggerConnectionImpl::ThreadEntry(uword args) {
- NotifyThreadStarted();
- ListenSocket* listen_socket =
- reinterpret_cast<ListenSocket*>(DebuggerConnectionHandler::listener_fd_);
- SOCKET client_socket = accept(listen_socket->socket(), NULL, NULL);
- if (client_socket == INVALID_SOCKET) {
- FATAL("Accepting new debugger connection failed.\n");
- }
- ClientSocket* socket = new ClientSocket(client_socket);
- DebuggerConnectionHandler::AcceptDbgConnection(
- reinterpret_cast<intptr_t>(socket));
- NotifyThreadFinished();
-}
-
-
-void DebuggerConnectionImpl::StartHandler(int port_number) {
- ASSERT(DebuggerConnectionHandler::listener_fd_ != -1);
- int result = Thread::Start(&DebuggerConnectionImpl::ThreadEntry, 0);
- if (result != 0) {
- FATAL1("Failed to start debugger connection handler thread: %d\n", result);
- }
- WaitForThreadStarted();
-}
-
-
-void DebuggerConnectionImpl::StopHandler(intptr_t debug_fd) {
- Send(debug_fd, NULL, 0);
- WaitForThreadFinished();
-}
-
-
-intptr_t DebuggerConnectionImpl::Send(intptr_t socket,
- const char* buf,
- int len) {
- ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(socket);
- return send(client_socket->socket(), buf, len, 0);
-}
-
-
-intptr_t DebuggerConnectionImpl::Receive(intptr_t socket, char* buf, int len) {
- ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(socket);
- return recv(client_socket->socket(), buf, len, 0);
-}
-
-} // namespace bin
-} // namespace dart
-
-#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/bin/dbg_connection_win.h b/runtime/bin/dbg_connection_win.h
deleted file mode 100644
index 8f5d0c6..0000000
--- a/runtime/bin/dbg_connection_win.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_CONNECTION_WIN_H_
-#define BIN_DBG_CONNECTION_WIN_H_
-
-#include "bin/lockers.h"
-#include "bin/thread.h"
-
-namespace dart {
-namespace bin {
-
-class DebuggerConnectionImpl {
- public:
- static void StartHandler(int port_number);
- static void StopHandler(intptr_t debug_fd);
- static intptr_t Send(intptr_t socket, const char* buf, int len);
- static intptr_t Receive(intptr_t socket, char* buf, int len);
-
- private:
- static void ThreadEntry(uword args);
- static void NotifyThreadStarted();
- static void WaitForThreadStarted();
- static void NotifyThreadFinished();
- static void WaitForThreadFinished();
-
- static Monitor* handler_monitor_;
- static ThreadId handler_thread_id_;
- static bool handler_thread_running_;
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_CONNECTION_WIN_H_
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
deleted file mode 100644
index d0f13d7..0000000
--- a/runtime/bin/dbg_message.cc
+++ /dev/null
@@ -1,1431 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "bin/dbg_connection.h"
-#include "bin/dbg_message.h"
-#include "bin/dartutils.h"
-#include "bin/lockers.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-#include "platform/utils.h"
-
-#include "include/dart_api.h"
-
-
-namespace dart {
-namespace bin {
-
-bool MessageParser::IsValidMessage() const {
- if (buf_length_ == 0) {
- return false;
- }
- dart::JSONReader msg_reader(buf_);
- return msg_reader.EndOfObject() != NULL;
-}
-
-
-int MessageParser::MessageId() const {
- dart::JSONReader r(buf_);
- r.Seek("id");
- if (r.Type() == dart::JSONReader::kInteger) {
- return atoi(r.ValueChars());
- } else {
- return -1;
- }
-}
-
-
-const char* MessageParser::Params() const {
- dart::JSONReader r(buf_);
- r.Seek("params");
- if (r.Type() == dart::JSONReader::kObject) {
- return r.ValueChars();
- } else {
- return NULL;
- }
-}
-
-
-bool MessageParser::HasParam(const char* name) const {
- const char* params = Params();
- ASSERT(params != NULL);
- dart::JSONReader r(params);
- return r.Seek(name);
-}
-
-
-intptr_t MessageParser::GetIntParam(const char* name) const {
- const char* params = Params();
- ASSERT(params != NULL);
- dart::JSONReader r(params);
- r.Seek(name);
- ASSERT(r.Type() == dart::JSONReader::kInteger);
- return strtol(r.ValueChars(), NULL, 10);
-}
-
-
-int64_t MessageParser::GetInt64Param(const char* name) const {
- const char* params = Params();
- ASSERT(params != NULL);
- dart::JSONReader r(params);
- r.Seek(name);
- ASSERT(r.Type() == dart::JSONReader::kInteger);
- return strtoll(r.ValueChars(), NULL, 10);
-}
-
-
-intptr_t MessageParser::GetOptIntParam(const char* name,
- intptr_t default_val) const {
- const char* params = Params();
- ASSERT(params != NULL);
- dart::JSONReader r(params);
- r.Seek(name);
- if (r.Type() == dart::JSONReader::kInteger) {
- return strtol(r.ValueChars(), NULL, 10);
- } else {
- return default_val;
- }
-}
-
-
-static const char* GetStringChars(Dart_Handle str) {
- ASSERT(Dart_IsString(str));
- const char* chars;
- Dart_Handle res = Dart_StringToCString(str, &chars);
- ASSERT(!Dart_IsError(res));
- return chars;
-}
-
-
-static int64_t GetIntValue(Dart_Handle int_handle) {
- int64_t int64_val = -1;
- ASSERT(Dart_IsInteger(int_handle));
- Dart_Handle res = Dart_IntegerToInt64(int_handle, &int64_val);
- ASSERT_NOT_ERROR(res);
- return int64_val;
-}
-
-
-char* MessageParser::GetStringParam(const char* name) const {
- const char* params = Params();
- ASSERT(params != NULL);
- dart::JSONReader pr(params);
- pr.Seek(name);
- if (pr.Type() != dart::JSONReader::kString) {
- return NULL;
- }
- intptr_t buflen = pr.ValueLen() + 1;
- char* param_chars = reinterpret_cast<char*>(malloc(buflen));
- pr.GetDecodedValueChars(param_chars, buflen);
- return param_chars;
-}
-
-
-static void FormatEncodedCharsTrunc(dart::TextBuffer* buf,
- Dart_Handle str,
- intptr_t max_chars) {
- intptr_t str_len = 0;
- Dart_Handle res = Dart_StringLength(str, &str_len);
- ASSERT_NOT_ERROR(res);
- intptr_t num_chars = (str_len > max_chars) ? max_chars : str_len;
- uint16_t* codeunits =
- reinterpret_cast<uint16_t*>(malloc(num_chars * sizeof(uint16_t)));
- ASSERT(codeunits != NULL);
- intptr_t actual_len = num_chars;
- res = Dart_StringToUTF16(str, codeunits, &actual_len);
- ASSERT_NOT_ERROR(res);
- ASSERT(num_chars == actual_len);
- for (int i = 0; i < num_chars; i++) {
- buf->EscapeAndAddCodeUnit(codeunits[i]);
- }
- if (str_len > max_chars) {
- buf->Printf("...");
- }
- free(codeunits);
-}
-
-
-static void FormatEncodedChars(dart::TextBuffer* buf, Dart_Handle str) {
- intptr_t str_len = 0;
- Dart_Handle res = Dart_StringLength(str, &str_len);
- ASSERT_NOT_ERROR(res);
- uint16_t* codeunits =
- reinterpret_cast<uint16_t*>(malloc(str_len * sizeof(uint16_t)));
- ASSERT(codeunits != NULL);
- intptr_t actual_len = str_len;
- res = Dart_StringToUTF16(str, codeunits, &actual_len);
- ASSERT_NOT_ERROR(res);
- ASSERT(str_len == actual_len);
- for (int i = 0; i < str_len; i++) {
- buf->EscapeAndAddCodeUnit(codeunits[i]);
- }
- free(codeunits);
-}
-
-
-static void FormatEncodedString(dart::TextBuffer* buf, Dart_Handle str) {
- buf->AddChar('\"');
- FormatEncodedChars(buf, str);
- buf->AddChar('\"');
-}
-
-
-static void FormatTextualValue(dart::TextBuffer* buf,
- Dart_Handle object,
- intptr_t max_chars,
- bool expand_list);
-
-
-static void FormatTextualListValue(dart::TextBuffer* buf,
- Dart_Handle list,
- intptr_t max_chars) {
- intptr_t len = 0;
- Dart_Handle res = Dart_ListLength(list, &len);
- ASSERT_NOT_ERROR(res);
- const intptr_t initial_buffer_length = buf->length();
- // Maximum number of characters we print for array elements.
- const intptr_t max_buffer_length = initial_buffer_length + max_chars;
- buf->Printf("[");
- for (int i = 0; i < len; i++) {
- if (i > 0) {
- buf->Printf(", ");
- }
- Dart_Handle elem = Dart_ListGetAt(list, i);
- const intptr_t max_element_chars = 50;
- FormatTextualValue(buf, elem, max_element_chars, false);
- if (buf->length() > max_buffer_length) {
- buf->Printf(", ...");
- break;
- }
- }
- buf->Printf("]");
-}
-
-
-static void FormatTextualValue(dart::TextBuffer* buf,
- Dart_Handle object,
- intptr_t max_chars,
- bool expand_list) {
- ASSERT(!Dart_IsError(object));
- if (Dart_IsList(object)) {
- if (expand_list) {
- FormatTextualListValue(buf, object, max_chars);
- } else {
- buf->Printf("[...]");
- }
- } else if (Dart_IsNull(object)) {
- buf->Printf("null");
- } else if (Dart_IsString(object)) {
- buf->Printf("\\\"");
- FormatEncodedCharsTrunc(buf, object, max_chars);
- buf->Printf("\\\"");
- } else if (Dart_IsNumber(object) || Dart_IsBoolean(object)) {
- Dart_Handle text = Dart_ToString(object);
- ASSERT(!Dart_IsNull(text) && !Dart_IsError(text));
- FormatEncodedCharsTrunc(buf, text, max_chars);
- } else {
- Dart_Handle type = Dart_InstanceGetType(object);
- ASSERT_NOT_ERROR(type);
- type = Dart_ToString(type);
- ASSERT_NOT_ERROR(type);
- buf->Printf("object of type ");
- FormatEncodedCharsTrunc(buf, type, max_chars);
- }
-}
-
-
-static void FormatValue(dart::TextBuffer* buf, Dart_Handle object) {
- bool print_text_field = true;
- if (Dart_IsNumber(object)) {
- buf->Printf("\"kind\":\"number\"");
- } else if (Dart_IsString(object)) {
- buf->Printf("\"kind\":\"string\"");
- } else if (Dart_IsBoolean(object)) {
- buf->Printf("\"kind\":\"boolean\"");
- } else if (Dart_IsList(object)) {
- intptr_t len = 0;
- Dart_Handle res = Dart_ListLength(object, &len);
- ASSERT_NOT_ERROR(res);
- buf->Printf("\"kind\":\"list\",\"length\":%" Pd "", len);
- } else if (Dart_IsClosure(object)) {
- Dart_Handle name, signature;
- Dart_CodeLocation location;
- Dart_Handle res = Dart_GetClosureInfo(object, &name, &signature, &location);
- ASSERT_NOT_ERROR(res);
- buf->Printf("\"kind\":\"function\",\"name\":\"%s\"", GetStringChars(name));
- buf->Printf(",\"signature\":\"%s\"", GetStringChars(signature));
- if (!Dart_IsNull(location.script_url)) {
- ASSERT(Dart_IsString(location.script_url));
- buf->Printf(",\"location\": { \"url\":");
- FormatEncodedString(buf, location.script_url);
- buf->Printf(",\"libraryId\":%d,", location.library_id);
- buf->Printf("\"tokenOffset\":%d}", location.token_pos);
- }
- print_text_field = false;
- } else {
- buf->Printf("\"kind\":\"object\"");
- intptr_t class_id = 0;
- Dart_Handle res = Dart_GetObjClassId(object, &class_id);
- if (!Dart_IsError(res)) {
- buf->Printf(",\"classId\":%" Pd "", class_id);
- }
- }
- if (print_text_field) {
- buf->Printf(",\"text\":\"");
- const intptr_t max_chars = 1024;
- FormatTextualValue(buf, object, max_chars, true);
- buf->Printf("\"");
- }
-}
-
-
-static void FormatValueObj(dart::TextBuffer* buf, Dart_Handle object) {
- buf->Printf("{");
- FormatValue(buf, object);
- buf->Printf("}");
-}
-
-
-static void FormatRemoteObj(dart::TextBuffer* buf, Dart_Handle object) {
- intptr_t obj_id = Dart_CacheObject(object);
- ASSERT(obj_id >= 0);
- buf->Printf("{\"objectId\":%" Pd ",", obj_id);
- FormatValue(buf, object);
- buf->Printf("}");
-}
-
-
-static void FormatNamedValue(dart::TextBuffer* buf,
- Dart_Handle object_name,
- Dart_Handle object) {
- ASSERT(Dart_IsString(object_name));
- buf->Printf("{\"name\":\"%s\",", GetStringChars(object_name));
- buf->Printf("\"value\":");
- FormatRemoteObj(buf, object);
- buf->Printf("}");
-}
-
-
-static void FormatNamedValueList(dart::TextBuffer* buf,
- Dart_Handle obj_list) {
- ASSERT(Dart_IsList(obj_list));
- intptr_t list_length = 0;
- Dart_Handle res = Dart_ListLength(obj_list, &list_length);
- ASSERT_NOT_ERROR(res);
- ASSERT(list_length % 2 == 0);
- buf->Printf("[");
- for (int i = 0; i + 1 < list_length; i += 2) {
- Dart_Handle name_handle = Dart_ListGetAt(obj_list, i);
- ASSERT_NOT_ERROR(name_handle);
- Dart_Handle value_handle = Dart_ListGetAt(obj_list, i + 1);
- ASSERT_NOT_ERROR(value_handle);
- if (i > 0) {
- buf->Printf(",");
- }
- FormatNamedValue(buf, name_handle, value_handle);
- }
- buf->Printf("]");
-}
-
-
-static const char* FormatClassProps(dart::TextBuffer* buf,
- intptr_t cls_id) {
- Dart_Handle name, static_fields;
- intptr_t super_id = -1;
- intptr_t library_id = -1;
- Dart_Handle res =
- Dart_GetClassInfo(cls_id, &name, &library_id, &super_id, &static_fields);
- RETURN_IF_ERROR(res);
- RETURN_IF_ERROR(name);
- buf->Printf("{\"name\":\"%s\",", GetStringChars(name));
- if (super_id > 0) {
- buf->Printf("\"superclassId\":%" Pd ",", super_id);
- }
- buf->Printf("\"libraryId\":%" Pd ",", library_id);
- RETURN_IF_ERROR(static_fields);
- buf->Printf("\"fields\":");
- FormatNamedValueList(buf, static_fields);
- buf->Printf("}");
- return NULL;
-}
-
-
-static const char* FormatLibraryProps(dart::TextBuffer* buf,
- intptr_t lib_id) {
- Dart_Handle url = Dart_GetLibraryURL(lib_id);
- RETURN_IF_ERROR(url);
- buf->Printf("{\"url\":");
- FormatEncodedString(buf, url);
-
- // Whether debugging is enabled.
- bool is_debuggable = false;
- Dart_Handle res = Dart_GetLibraryDebuggable(lib_id, &is_debuggable);
- RETURN_IF_ERROR(res);
- buf->Printf(",\"debuggingEnabled\":%s",
- is_debuggable ? "\"true\"" : "\"false\"");
-
- // Imports and prefixes.
- Dart_Handle import_list = Dart_GetLibraryImports(lib_id);
- RETURN_IF_ERROR(import_list);
- ASSERT(Dart_IsList(import_list));
- intptr_t list_length = 0;
- res = Dart_ListLength(import_list, &list_length);
- RETURN_IF_ERROR(res);
- buf->Printf(",\"imports\":[");
- for (intptr_t i = 0; i + 1 < list_length; i += 2) {
- Dart_Handle lib_id = Dart_ListGetAt(import_list, i + 1);
- ASSERT_NOT_ERROR(lib_id);
- buf->Printf("%s{\"libraryId\":%" Pd64 ",",
- (i > 0) ? ",": "",
- GetIntValue(lib_id));
-
- Dart_Handle name = Dart_ListGetAt(import_list, i);
- ASSERT_NOT_ERROR(name);
- buf->Printf("\"prefix\":\"%s\"}",
- Dart_IsNull(name) ? "" : GetStringChars(name));
- }
- buf->Printf("],");
-
- // Global variables in the library.
- Dart_Handle global_vars = Dart_GetLibraryFields(lib_id);
- RETURN_IF_ERROR(global_vars);
- buf->Printf("\"globals\":");
- FormatNamedValueList(buf, global_vars);
- buf->Printf("}");
- return NULL;
-}
-
-
-static const char* FormatObjProps(dart::TextBuffer* buf,
- Dart_Handle object) {
- intptr_t class_id;
- if (Dart_IsNull(object)) {
- buf->Printf("{\"classId\":-1,\"fields\":[]}");
- return NULL;
- }
- Dart_Handle res = Dart_GetObjClassId(object, &class_id);
- RETURN_IF_ERROR(res);
- buf->Printf("{\"classId\": %" Pd ",", class_id);
- buf->Printf("\"kind\":\"object\",\"fields\":");
- Dart_Handle fields = Dart_GetInstanceFields(object);
- RETURN_IF_ERROR(fields);
- FormatNamedValueList(buf, fields);
- buf->Printf("}");
- return NULL;
-}
-
-
-static const char* FormatListSlice(dart::TextBuffer* buf,
- Dart_Handle list,
- intptr_t list_length,
- intptr_t index,
- intptr_t slice_length) {
- intptr_t end_index = index + slice_length;
- ASSERT(end_index <= list_length);
- buf->Printf("{\"index\":%" Pd ",", index);
- buf->Printf("\"length\":%" Pd ",", slice_length);
- buf->Printf("\"elements\":[");
- for (intptr_t i = index; i < end_index; i++) {
- Dart_Handle value = Dart_ListGetAt(list, i);
- if (i > index) {
- buf->Printf(",");
- }
- FormatValueObj(buf, value);
- }
- buf->Printf("]}");
- return NULL;
-}
-
-
-static void FormatLocationFromTrace(dart::TextBuffer* msg,
- Dart_StackTrace trace,
- const char* prefix) {
- intptr_t trace_len = 0;
- Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
- ASSERT_NOT_ERROR(res);
- if (trace_len == 0) {
- return;
- }
- Dart_ActivationFrame frame;
- res = Dart_GetActivationFrame(trace, 0, &frame);
- ASSERT_NOT_ERROR(res);
- Dart_CodeLocation location;
- res = Dart_ActivationFrameGetLocation(frame, NULL, NULL, &location);
- ASSERT_NOT_ERROR(res);
- if (!Dart_IsNull(location.script_url)) {
- ASSERT(Dart_IsString(location.script_url));
- msg->Printf("%s\"location\": { \"url\":", prefix);
- FormatEncodedString(msg, location.script_url);
- msg->Printf(",\"libraryId\":%d,", location.library_id);
- msg->Printf("\"tokenOffset\":%d}", location.token_pos);
- }
-}
-
-
-static void FormatCallFrames(dart::TextBuffer* msg, Dart_StackTrace trace) {
- intptr_t trace_len = 0;
- Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
- ASSERT_NOT_ERROR(res);
- msg->Printf("\"callFrames\" : [ ");
- for (int i = 0; i < trace_len; i++) {
- Dart_ActivationFrame frame;
- res = Dart_GetActivationFrame(trace, i, &frame);
- ASSERT_NOT_ERROR(res);
- Dart_Handle func_name;
- Dart_Handle func;
- Dart_CodeLocation location;
- res = Dart_ActivationFrameGetLocation(frame, &func_name, &func, &location);
- ASSERT_NOT_ERROR(res);
- ASSERT(Dart_IsString(func_name));
- msg->Printf("%s{\"functionName\":", (i > 0) ? "," : "");
- FormatEncodedString(msg, func_name);
- if (!Dart_IsNull(location.script_url)) {
- ASSERT(Dart_IsString(location.script_url));
- msg->Printf(",\"location\": { \"url\":");
- FormatEncodedString(msg, location.script_url);
- msg->Printf(",\"libraryId\":%d,", location.library_id);
- msg->Printf("\"tokenOffset\":%d}", location.token_pos);
- }
- ASSERT_NOT_ERROR(func);
- Dart_Handle origin = Dart_GetFunctionOrigin(func);
- ASSERT_NOT_ERROR(origin);
- if (Dart_IsInteger(origin)) {
- int64_t class_id = GetIntValue(origin);
- msg->Printf(",\"classId\":%" Pd64 "", class_id);
- }
- Dart_Handle locals = Dart_GetLocalVariables(frame);
- ASSERT_NOT_ERROR(locals);
- msg->Printf(",\"locals\":");
- FormatNamedValueList(msg, locals);
- msg->Printf("}");
- }
- msg->Printf("]");
-}
-
-
-typedef bool (*CommandHandler)(DbgMessage* msg);
-
-struct JSONDebuggerCommand {
- const char* cmd_string;
- CommandHandler handler_function;
-};
-
-
-static JSONDebuggerCommand debugger_commands[] = {
- { "resume", DbgMessage::HandleResumeCmd },
- { "stepInto", DbgMessage::HandleStepIntoCmd },
- { "stepOut", DbgMessage::HandleStepOutCmd },
- { "stepOver", DbgMessage::HandleStepOverCmd },
- { "getLibraries", DbgMessage::HandleGetLibrariesCmd },
- { "getClassProperties", DbgMessage::HandleGetClassPropsCmd },
- { "getLibraryProperties", DbgMessage::HandleGetLibPropsCmd },
- { "setLibraryProperties", DbgMessage::HandleSetLibPropsCmd },
- { "evaluateExpr", DbgMessage::HandleEvaluateExprCmd },
- { "getObjectProperties", DbgMessage::HandleGetObjPropsCmd },
- { "getListElements", DbgMessage::HandleGetListCmd },
- { "getGlobalVariables", DbgMessage::HandleGetGlobalsCmd },
- { "getScriptURLs", DbgMessage::HandleGetScriptURLsCmd },
- { "getScriptSource", DbgMessage::HandleGetSourceCmd },
- { "getLineNumberTable", DbgMessage::HandleGetLineNumbersCmd },
- { "getStackTrace", DbgMessage::HandleGetStackTraceCmd },
- { "setBreakpoint", DbgMessage::HandleSetBpCmd },
- { "setPauseOnException", DbgMessage::HandlePauseOnExcCmd },
- { "removeBreakpoint", DbgMessage::HandleRemBpCmd },
- { NULL, NULL }
-};
-
-
-bool DbgMessage::HandleMessage() {
- // Dispatch to the appropriate handler for the command.
- int max_index = (sizeof(debugger_commands) / sizeof(JSONDebuggerCommand));
- ASSERT(cmd_idx_ < max_index);
- return (*debugger_commands[cmd_idx_].handler_function)(this);
-}
-
-
-void DbgMessage::SendReply(dart::TextBuffer* reply) {
- DebuggerConnectionHandler::SendMsg(debug_fd(), reply);
-}
-
-
-void DbgMessage::SendErrorReply(int msg_id, const char* err_msg) {
- DebuggerConnectionHandler::SendError(debug_fd(), msg_id, err_msg);
-}
-
-
-bool DbgMessage::HandleResumeCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d }", msg_id);
- in_msg->SendReply(&msg);
- return true;
-}
-
-
-bool DbgMessage::HandleStepIntoCmd(DbgMessage* in_msg) {
- Dart_Handle res = Dart_SetStepInto();
- ASSERT_NOT_ERROR(res);
- return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleStepOutCmd(DbgMessage* in_msg) {
- Dart_Handle res = Dart_SetStepOut();
- ASSERT_NOT_ERROR(res);
- return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleStepOverCmd(DbgMessage* in_msg) {
- Dart_Handle res = Dart_SetStepOver();
- ASSERT_NOT_ERROR(res);
- return HandleResumeCmd(in_msg);
-}
-
-
-bool DbgMessage::HandleGetLibrariesCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d, \"result\": { \"libraries\": [", msg_id);
- Dart_Handle lib_ids = Dart_GetLibraryIds();
- ASSERT_NOT_ERROR(lib_ids);
- intptr_t num_libs;
- Dart_Handle res = Dart_ListLength(lib_ids, &num_libs);
- ASSERT_NOT_ERROR(res);
- for (intptr_t i = 0; i < num_libs; i++) {
- Dart_Handle lib_id_handle = Dart_ListGetAt(lib_ids, i);
- ASSERT(Dart_IsInteger(lib_id_handle));
- int64_t lib_id = GetIntValue(lib_id_handle);
- ASSERT((lib_id >= kIntptrMin) && (lib_id <= kIntptrMax));
- Dart_Handle lib_url = Dart_GetLibraryURL(static_cast<intptr_t>(lib_id));
- ASSERT_NOT_ERROR(lib_url);
- ASSERT(Dart_IsString(lib_url));
- msg.Printf("%s{\"id\":%" Pd64 ",\"url\":", (i == 0) ? "" : ", ", lib_id);
- FormatEncodedString(&msg, lib_url);
- msg.Printf("}");
- }
- msg.Printf("]}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetClassPropsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t cls_id = msg_parser.GetIntParam("classId");
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\":", msg_id);
- const char* err = FormatClassProps(&msg, cls_id);
- if (err != NULL) {
- in_msg->SendErrorReply(msg_id, err);
- return false;
- }
- msg.Printf("}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetLibPropsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\":", msg_id);
- const char* err = FormatLibraryProps(&msg, lib_id);
- if (err != NULL) {
- in_msg->SendErrorReply(msg_id, err);
- return false;
- }
- msg.Printf("}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleSetLibPropsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- const char* enable_request = msg_parser.GetStringParam("debuggingEnabled");
- bool enable;
- if (strcmp(enable_request, "true") == 0) {
- enable = true;
- } else if (strcmp(enable_request, "false") == 0) {
- enable = false;
- } else {
- in_msg->SendErrorReply(msg_id, "illegal argument for 'debuggingEnabled'");
- return false;
- }
- Dart_Handle res = Dart_SetLibraryDebuggable(lib_id, enable);
- if (Dart_IsError(res)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(res));
- return false;
- }
- bool enabled = false;
- res = Dart_GetLibraryDebuggable(lib_id, &enabled);
- if (Dart_IsError(res)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(res));
- return false;
- }
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\": {\"debuggingEnabled\": \"%s\"}}",
- msg_id,
- enabled ? "true" : "false");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleEvaluateExprCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- Dart_Handle target = Dart_Null();
- Dart_ActivationFrame frame = NULL;
-
- if (msg_parser.HasParam("libraryId")) {
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- target = Dart_GetLibraryFromId(lib_id);
- } else if (msg_parser.HasParam("classId")) {
- intptr_t cls_id = msg_parser.GetIntParam("classId");
- target = Dart_GetClassFromId(cls_id);
- } else if (msg_parser.HasParam("objectId")) {
- intptr_t obj_id = msg_parser.GetIntParam("objectId");
- target = Dart_GetCachedObject(obj_id);
- } else if (msg_parser.HasParam("frameId")) {
- intptr_t frame_index = msg_parser.GetIntParam("frameId");
- Dart_Handle res;
- Dart_StackTrace stack_trace;
- res = Dart_GetStackTrace(&stack_trace);
- ASSERT_NOT_ERROR(res);
- intptr_t trace_length = 0;
- res = Dart_StackTraceLength(stack_trace, &trace_length);
- ASSERT_NOT_ERROR(res);
- if (frame_index >= trace_length) {
- in_msg->SendErrorReply(msg_id, "illegal frame index");
- return false;
- }
- res = Dart_GetActivationFrame(stack_trace, frame_index, &frame);
- ASSERT_NOT_ERROR(res);
- } else {
- in_msg->SendErrorReply(msg_id, "illegal evaluation target");
- return false;
- }
-
- char* expr_chars = msg_parser.GetStringParam("expression");
- Dart_Handle expr = Dart_NewStringFromCString(expr_chars);
- if (Dart_IsError(expr)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(expr));
- return false;
- }
-
- Dart_Handle eval_result = Dart_Null();
- if (frame != NULL) {
- eval_result = Dart_ActivationFrameEvaluate(frame, expr);
- } else {
- if (Dart_IsError(target)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(target));
- return false;
- }
- eval_result = Dart_EvaluateExpr(target, expr);
- }
- if (Dart_IsError(eval_result)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(eval_result));
- return false;
- }
-
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\":", msg_id);
- FormatRemoteObj(&msg, eval_result);
- msg.Printf("}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetObjPropsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t obj_id = msg_parser.GetIntParam("objectId");
- Dart_Handle obj = Dart_GetCachedObject(obj_id);
- if (Dart_IsError(obj)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(obj));
- return false;
- }
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\":", msg_id);
- const char* err = FormatObjProps(&msg, obj);
- if (err != NULL) {
- in_msg->SendErrorReply(msg_id, err);
- return false;
- }
- msg.Printf("}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetListCmd(DbgMessage* in_msg) {
- const intptr_t kDefaultSliceLength = 100;
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t obj_id = msg_parser.GetIntParam("objectId");
- Dart_Handle list = Dart_GetCachedObject(obj_id);
- if (Dart_IsError(list)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(list));
- return false;
- }
- if (!Dart_IsList(list)) {
- in_msg->SendErrorReply(msg_id, "object is not a list");
- return false;
- }
- intptr_t list_length = 0;
- Dart_Handle res = Dart_ListLength(list, &list_length);
- if (Dart_IsError(res)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(res));
- return false;
- }
-
- intptr_t index = msg_parser.GetIntParam("index");
- if (index < 0) {
- index = 0;
- } else if (index > list_length) {
- index = list_length;
- }
-
- // If no slice length is given, get only one element. If slice length
- // is given as 0, get entire list.
- intptr_t slice_length = msg_parser.GetOptIntParam("length", 1);
- if (slice_length == 0) {
- slice_length = list_length - index;
- }
- if ((index + slice_length) > list_length) {
- slice_length = list_length - index;
- }
- ASSERT(slice_length >= 0);
- if (slice_length > kDefaultSliceLength) {
- slice_length = kDefaultSliceLength;
- }
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\":", msg_id);
- if (slice_length == 1) {
- Dart_Handle value = Dart_ListGetAt(list, index);
- FormatRemoteObj(&msg, value);
- } else {
- FormatListSlice(&msg, list, list_length, index, slice_length);
- }
- msg.Printf("}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetGlobalsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- dart::TextBuffer msg(64);
- msg.Printf("{\"id\":%d, \"result\": { \"globals\":", msg_id);
- Dart_Handle globals = Dart_GetGlobalVariables(lib_id);
- ASSERT_NOT_ERROR(globals);
- FormatNamedValueList(&msg, globals);
- msg.Printf("}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetScriptURLsCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- dart::TextBuffer msg(64);
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- Dart_Handle lib_url = Dart_GetLibraryURL(lib_id);
- ASSERT_NOT_ERROR(lib_url);
- Dart_Handle urls = Dart_GetScriptURLs(lib_url);
- if (Dart_IsError(urls)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(urls));
- return false;
- }
- ASSERT(Dart_IsList(urls));
- intptr_t num_urls = 0;
- Dart_ListLength(urls, &num_urls);
- msg.Printf("{ \"id\": %d, ", msg_id);
- msg.Printf("\"result\": { \"urls\": [");
- for (int i = 0; i < num_urls; i++) {
- Dart_Handle script_url = Dart_ListGetAt(urls, i);
- if (i > 0) {
- msg.Printf(",");
- }
- FormatEncodedString(&msg, script_url);
- }
- msg.Printf("]}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetSourceCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- dart::TextBuffer msg(64);
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- char* url_chars = msg_parser.GetStringParam("url");
- ASSERT(url_chars != NULL);
- Dart_Handle url = DartUtils::NewString(url_chars);
- ASSERT_NOT_ERROR(url);
- free(url_chars);
- url_chars = NULL;
- Dart_Handle source = Dart_ScriptGetSource(lib_id, url);
- if (Dart_IsError(source)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(source));
- return false;
- }
- msg.Printf("{ \"id\": %d, ", msg_id);
- msg.Printf("\"result\": { \"text\": ");
- FormatEncodedString(&msg, source);
- msg.Printf("}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetLineNumbersCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- dart::TextBuffer msg(64);
- intptr_t lib_id = msg_parser.GetIntParam("libraryId");
- char* url_chars = msg_parser.GetStringParam("url");
- ASSERT(url_chars != NULL);
- Dart_Handle url = DartUtils::NewString(url_chars);
- ASSERT_NOT_ERROR(url);
- free(url_chars);
- url_chars = NULL;
- Dart_Handle info = Dart_ScriptGetTokenInfo(lib_id, url);
- if (Dart_IsError(info)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(info));
- return false;
- }
- ASSERT(Dart_IsList(info));
- intptr_t info_len = 0;
- Dart_Handle res = Dart_ListLength(info, &info_len);
- ASSERT_NOT_ERROR(res);
- msg.Printf("{ \"id\": %d, ", msg_id);
- msg.Printf("\"result\": { \"lines\": [");
- Dart_Handle elem;
- intptr_t num_elems = 0;
- for (intptr_t i = 0; i < info_len; i++) {
- elem = Dart_ListGetAt(info, i);
- if (Dart_IsNull(elem)) {
- msg.Printf((i == 0) ? "[" : "], [");
- num_elems = 0;
- } else {
- ASSERT(Dart_IsInteger(elem));
- int64_t value = GetIntValue(elem);
- if (num_elems == 0) {
- msg.Printf("%" Pd64 "", value);
- } else {
- msg.Printf(",%" Pd64 "", value);
- }
- num_elems++;
- }
- }
- msg.Printf("]]}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleGetStackTraceCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- Dart_StackTrace trace;
- Dart_Handle res = Dart_GetStackTrace(&trace);
- ASSERT_NOT_ERROR(res);
- dart::TextBuffer msg(128);
- msg.Printf("{ \"id\": %d, \"result\": {", msg_id);
- FormatCallFrames(&msg, trace);
- msg.Printf("}}");
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleSetBpCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- char* url_chars = msg_parser.GetStringParam("url");
- ASSERT(url_chars != NULL);
- Dart_Handle url = DartUtils::NewString(url_chars);
- ASSERT_NOT_ERROR(url);
- free(url_chars);
- url_chars = NULL;
- intptr_t line_number = msg_parser.GetIntParam("line");
- Dart_Handle bp_id = Dart_SetBreakpoint(url, line_number);
- if (Dart_IsError(bp_id)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(bp_id));
- return false;
- }
- ASSERT(Dart_IsInteger(bp_id));
- uint64_t bp_id_value;
- Dart_Handle res = Dart_IntegerToUint64(bp_id, &bp_id_value);
- ASSERT_NOT_ERROR(res);
- dart::TextBuffer msg(64);
- msg.Printf("{ \"id\": %d, \"result\": { \"breakpointId\": %" Pu64 " }}",
- msg_id, bp_id_value);
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandlePauseOnExcCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- char* exc_chars = msg_parser.GetStringParam("exceptions");
- Dart_ExceptionPauseInfo info = kNoPauseOnExceptions;
- if (strcmp(exc_chars, "none") == 0) {
- info = kNoPauseOnExceptions;
- } else if (strcmp(exc_chars, "all") == 0) {
- info = kPauseOnAllExceptions;
- } else if (strcmp(exc_chars, "unhandled") == 0) {
- info = kPauseOnUnhandledExceptions;
- } else {
- in_msg->SendErrorReply(msg_id, "illegal value for parameter 'exceptions'");
- return false;
- }
- Dart_Handle res = Dart_SetExceptionPauseInfo(info);
- ASSERT_NOT_ERROR(res);
- dart::TextBuffer msg(32);
- msg.Printf("{ \"id\": %d }", msg_id);
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-bool DbgMessage::HandleRemBpCmd(DbgMessage* in_msg) {
- ASSERT(in_msg != NULL);
- MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
- int msg_id = msg_parser.MessageId();
- int bpt_id = msg_parser.GetIntParam("breakpointId");
- Dart_Handle res = Dart_RemoveBreakpoint(bpt_id);
- if (Dart_IsError(res)) {
- in_msg->SendErrorReply(msg_id, Dart_GetError(res));
- return false;
- }
- dart::TextBuffer msg(32);
- msg.Printf("{ \"id\": %d }", msg_id);
- in_msg->SendReply(&msg);
- return false;
-}
-
-
-void DbgMsgQueue::AddMessage(int32_t cmd_idx,
- const char* start,
- const char* end,
- intptr_t debug_fd) {
- if ((end > start) && ((end - start) < kMaxInt32)) {
- MonitorLocker ml(&msg_queue_lock_);
- DbgMessage* msg = new DbgMessage(cmd_idx, start, end, debug_fd);
- if (msglist_head_ == NULL) {
- ASSERT(msglist_tail_ == NULL);
- msglist_head_ = msg;
- msglist_tail_ = msg;
- ml.Notify();
- } else {
- ASSERT(msglist_tail_ != NULL);
- msglist_tail_->set_next(msg);
- msglist_tail_ = msg;
- }
- }
-}
-
-
-void DbgMsgQueue::Notify() {
- MonitorLocker ml(&msg_queue_lock_);
- ml.Notify();
-}
-
-
-bool DbgMsgQueue::HandlePendingMessages() {
- // Handle all available debug messages, up to a resume request.
- bool resume_requested = false;
- while (msglist_head_ != NULL && !resume_requested) {
- ASSERT(msglist_tail_ != NULL);
- DbgMessage* msg = msglist_head_;
- msglist_head_ = msglist_head_->next();
- if (msglist_head_ == NULL) {
- msglist_tail_ = NULL;
- }
- resume_requested = msg->HandleMessage();
- delete msg;
- }
- return resume_requested;
-}
-
-
-void DbgMsgQueue::MessageLoop() {
- MonitorLocker ml(&msg_queue_lock_);
- is_running_ = false;
-
- // Request notification on isolate messages. This allows us to
- // respond to vm service messages while at breakpoint.
- Dart_SetMessageNotifyCallback(DbgMsgQueueList::NotifyIsolate);
-
- while (true) {
- // Handle all available vm service messages, up to a resume
- // request.
- bool resume = false;
- while (!resume && Dart_HasServiceMessages()) {
- msg_queue_lock_.Exit();
- resume = Dart_HandleServiceMessages();
- msg_queue_lock_.Enter();
- }
- if (resume) {
- break;
- }
-
- // Handle all available debug messages, up to a resume request.
- if (HandlePendingMessages()) {
- break;
- }
-
- // Wait for more debug or vm service messages.
- Monitor::WaitResult res = ml.Wait();
- ASSERT(res == Monitor::kNotified);
- }
- Dart_SetMessageNotifyCallback(NULL);
- is_interrupted_ = false;
- is_running_ = true;
-}
-
-
-void DbgMsgQueue::InterruptIsolate() {
- Dart_Isolate isolate = Dart_GetIsolate(isolate_id_);
- MonitorLocker ml(&msg_queue_lock_);
- if (is_running_ && !is_interrupted_) {
- is_interrupted_ = true;
- Dart_InterruptIsolate(isolate);
- }
-}
-
-
-void DbgMsgQueue::QueueOutputMsg(dart::TextBuffer* msg) {
- queued_output_messages_.Printf("%s", msg->buf());
-}
-
-
-void DbgMsgQueue::SendQueuedMsgs() {
- if (queued_output_messages_.length() > 0) {
- DebuggerConnectionHandler::BroadcastMsg(&queued_output_messages_);
- queued_output_messages_.Clear();
- }
-}
-
-
-void DbgMsgQueue::SendBreakpointEvent(intptr_t bp_id,
- const Dart_CodeLocation& location) {
- dart::TextBuffer msg(128);
- msg.Printf("{ \"event\": \"paused\", \"params\": { ");
- msg.Printf("\"reason\": \"breakpoint\", ");
- msg.Printf("\"isolateId\": %" Pd64 "", isolate_id_);
- if (bp_id != ILLEGAL_BREAKPOINT_ID) {
- msg.Printf(",\"breakpointId\": %" Pd "", bp_id);
- }
- if (!Dart_IsNull(location.script_url)) {
- ASSERT(Dart_IsString(location.script_url));
- msg.Printf(",\"location\": { \"url\":");
- FormatEncodedString(&msg, location.script_url);
- msg.Printf(",\"libraryId\":%d,", location.library_id);
- msg.Printf("\"tokenOffset\":%d}", location.token_pos);
- }
- msg.Printf("}}");
- DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-// TODO(hausner): Remove stack trace parameter once we remove the stack
-// trace from the paused event in the wire protocol.
-void DbgMsgQueue::SendExceptionEvent(Dart_Handle exception,
- Dart_StackTrace stack_trace) {
- intptr_t exception_id = Dart_CacheObject(exception);
- ASSERT(exception_id >= 0);
- dart::TextBuffer msg(128);
- msg.Printf("{ \"event\": \"paused\", \"params\": {");
- msg.Printf("\"reason\": \"exception\", ");
- msg.Printf("\"isolateId\": %" Pd64 ", ", isolate_id_);
- msg.Printf("\"exception\":");
- FormatRemoteObj(&msg, exception);
- FormatLocationFromTrace(&msg, stack_trace, ", ");
- msg.Printf("}}");
- DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-// TODO(hausner): Remove stack trace parameter once we remove the stack
-// trace from the interrupted event in the wire protocol.
-void DbgMsgQueue::SendIsolateEvent(Dart_IsolateId isolate_id,
- Dart_IsolateEvent kind) {
- dart::TextBuffer msg(128);
- if (kind == kInterrupted) {
- Dart_StackTrace trace;
- Dart_Handle res = Dart_GetStackTrace(&trace);
- ASSERT_NOT_ERROR(res);
- msg.Printf("{ \"event\": \"paused\", \"params\": { ");
- msg.Printf("\"reason\": \"interrupted\", ");
- msg.Printf("\"isolateId\": %" Pd64 "", isolate_id);
- FormatLocationFromTrace(&msg, trace, ", ");
- msg.Printf("}}");
- } else {
- msg.Printf("{ \"event\": \"isolate\", \"params\": { ");
- if (kind == kCreated) {
- msg.Printf("\"reason\": \"created\", ");
- } else {
- ASSERT(kind == kShutdown);
- msg.Printf("\"reason\": \"shutdown\", ");
- }
- msg.Printf("\"id\": %" Pd64 " ", isolate_id);
- msg.Printf("}}");
- }
- DebuggerConnectionHandler::BroadcastMsg(&msg);
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::list_ = NULL;
-Mutex* DbgMsgQueueList::msg_queue_list_lock_ = new Mutex();
-
-
-void DbgMsgQueueList::Initialize() {
- // Setup handlers for isolate events, breakpoints, exceptions and
- // delayed breakpoints.
- Dart_SetIsolateEventHandler(IsolateEventHandler);
- Dart_SetPausedEventHandler(PausedEventHandler);
- Dart_SetBreakpointResolvedHandler(BptResolvedHandler);
- Dart_SetExceptionThrownHandler(ExceptionThrownHandler);
-}
-
-
-int32_t DbgMsgQueueList::LookupIsolateCommand(const char* buf,
- int32_t buflen) {
- // Check if we have a isolate specific debugger command.
- int32_t i = 0;
- while (debugger_commands[i].cmd_string != NULL) {
- if (strncmp(buf, debugger_commands[i].cmd_string, buflen) == 0) {
- return i;
- }
- i++;
- }
- return kInvalidCommand;
-}
-
-
-bool DbgMsgQueueList::AddIsolateMessage(Dart_IsolateId isolate_id,
- int32_t cmd_idx,
- const char* start,
- const char* end,
- intptr_t debug_fd) {
- MutexLocker ml(msg_queue_list_lock_);
- DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
- if (queue != NULL) {
- queue->AddMessage(cmd_idx, start, end, debug_fd);
- return true;
- }
- return false;
-}
-
-
-void DbgMsgQueueList::NotifyIsolate(Dart_Isolate isolate) {
- MutexLocker ml(msg_queue_list_lock_);
- Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
- DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
- if (queue != NULL) {
- queue->Notify();
- }
-}
-
-
-bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) {
- MutexLocker ml(msg_queue_list_lock_);
- DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
- if (queue != NULL) {
- queue->InterruptIsolate();
- return true;
- }
- return false;
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::AddIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(msg_queue_list_lock_);
-
- DbgMsgQueue* queue = new DbgMsgQueue(isolate_id, list_);
- ASSERT(queue != NULL);
- list_ = queue;
- return queue;
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(msg_queue_list_lock_);
- ASSERT(Dart_GetIsolate(isolate_id) == Dart_CurrentIsolate());
- return GetIsolateMsgQueueLocked(isolate_id);
-}
-
-
-DbgMsgQueue* DbgMsgQueueList::GetIsolateMsgQueueLocked(Dart_IsolateId id) {
- if (list_ == NULL) {
- return NULL; // No items in the list.
- }
-
- // Find message queue corresponding to isolate id.
- DbgMsgQueue* iterator = list_;
- while (iterator != NULL && iterator->isolate_id() != id) {
- iterator = iterator->next();
- }
- return iterator;
-}
-
-
-void DbgMsgQueueList::RemoveIsolateMsgQueue(Dart_IsolateId isolate_id) {
- MutexLocker ml(msg_queue_list_lock_);
- if (list_ == NULL) {
- return; // No items in the list.
- }
- DbgMsgQueue* queue = list_;
- if (queue->isolate_id() == isolate_id) {
- list_ = queue->next(); // Remove from list.
- delete queue; // Delete the message queue.
- return;
- } else {
- DbgMsgQueue* iterator = queue;
- queue = queue->next();
- while (queue != NULL) {
- if (queue->isolate_id() == isolate_id) {
- iterator->set_next(queue->next()); // Remove from list.
- delete queue; // Delete the message queue.
- return;
- }
- iterator = queue;
- queue = queue->next();
- }
- }
- UNREACHABLE();
-}
-
-
-void DbgMsgQueueList::ListIsolateIds(dart::TextBuffer* msg) {
- MutexLocker ml(msg_queue_list_lock_);
- if (list_ == NULL) {
- return; // No items in the list.
- }
- DbgMsgQueue* queue = list_;
- msg->Printf("%" Pd64 "", queue->isolate_id());
- queue = queue->next();
- while (queue != NULL) {
- msg->Printf(",%" Pd64 "", queue->isolate_id());
- queue = queue->next();
- }
-}
-
-
-void DbgMsgQueueList::BptResolvedHandler(Dart_IsolateId isolate_id,
- intptr_t bp_id,
- const Dart_CodeLocation& location) {
- Dart_EnterScope();
- dart::TextBuffer msg(128);
- msg.Printf("{ \"event\": \"breakpointResolved\", \"params\": {");
- msg.Printf("\"breakpointId\": %" Pd "", bp_id);
-
- msg.Printf(", \"isolateId\":%" Pd64 "", isolate_id);
- ASSERT(!Dart_IsNull(location.script_url));
- ASSERT(Dart_IsString(location.script_url));
- msg.Printf(", \"location\":{\"url\":");
- FormatEncodedString(&msg, location.script_url);
- msg.Printf(",\"libraryId\":%d", location.library_id);
- msg.Printf(",\"tokenOffset\":%d}}}", location.token_pos);
-
- DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
- ASSERT(msg_queue != NULL);
- msg_queue->QueueOutputMsg(&msg);
- Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::PausedEventHandler(Dart_IsolateId isolate_id,
- intptr_t bp_id,
- const Dart_CodeLocation& loc) {
- DebuggerConnectionHandler::WaitForConnection();
- Dart_EnterScope();
- DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
- ASSERT(msg_queue != NULL);
- msg_queue->SendQueuedMsgs();
- msg_queue->SendBreakpointEvent(bp_id, loc);
- msg_queue->MessageLoop();
- Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::ExceptionThrownHandler(Dart_IsolateId isolate_id,
- Dart_Handle exception,
- Dart_StackTrace stack_trace) {
- DebuggerConnectionHandler::WaitForConnection();
- Dart_EnterScope();
- DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
- ASSERT(msg_queue != NULL);
- msg_queue->SendQueuedMsgs();
- msg_queue->SendExceptionEvent(exception, stack_trace);
- msg_queue->MessageLoop();
- Dart_ExitScope();
-}
-
-
-void DbgMsgQueueList::IsolateEventHandler(Dart_IsolateId isolate_id,
- Dart_IsolateEvent kind) {
- if (kind == kCreated) {
- DebuggerConnectionHandler::WaitForConnection();
- Dart_EnterScope();
- DbgMsgQueue* msg_queue = AddIsolateMsgQueue(isolate_id);
- msg_queue->SendIsolateEvent(isolate_id, kind);
- Dart_ExitScope();
- } else {
- DebuggerConnectionHandler::WaitForConnection();
- DbgMsgQueue* msg_queue = GetIsolateMsgQueue(isolate_id);
- ASSERT(msg_queue != NULL);
- Dart_EnterScope();
- msg_queue->SendQueuedMsgs();
- msg_queue->SendIsolateEvent(isolate_id, kind);
- if (kind == kInterrupted) {
- msg_queue->MessageLoop();
- } else {
- ASSERT(kind == kShutdown);
- RemoveIsolateMsgQueue(isolate_id);
- }
- Dart_ExitScope();
- // If there is no receive message queue, do not wait for a connection, and
- // ignore the message.
- }
-}
-
-} // namespace bin
-} // namespace dart
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
deleted file mode 100644
index 0714174..0000000
--- a/runtime/bin/dbg_message.h
+++ /dev/null
@@ -1,282 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef BIN_DBG_MESSAGE_H_
-#define BIN_DBG_MESSAGE_H_
-
-#include "bin/builtin.h"
-#include "bin/thread.h"
-#include "bin/utils.h"
-
-#include "include/dart_tools_api.h"
-
-#include "platform/globals.h"
-#include "platform/json.h"
-
-
-namespace dart {
-namespace bin {
-
-// TODO(hausner): Need better error handling.
-#define ASSERT_NOT_ERROR(handle) \
- ASSERT(!Dart_IsError(handle))
-
-#define RETURN_IF_ERROR(handle) \
- if (Dart_IsError(handle)) { \
- return Dart_GetError(handle); \
- }
-
-
-// Class to parse a JSON debug command message.
-class MessageParser {
- public:
- MessageParser(const char* buf, int buf_length)
- : buf_(buf), buf_length_(buf_length) {
- }
- ~MessageParser() { }
-
- // Accessors.
- const char* buf() const { return buf_; }
-
- bool IsValidMessage() const;
- int MessageId() const;
-
- const char* Params() const;
- bool HasParam(const char* name) const;
- intptr_t GetIntParam(const char* name) const;
- int64_t GetInt64Param(const char* name) const;
- intptr_t GetOptIntParam(const char* name, intptr_t default_val) const;
-
- // GetStringParam mallocs the buffer that it returns. Caller must free.
- char* GetStringParam(const char* name) const;
-
- private:
- const char* buf_;
- int buf_length_;
-
- DISALLOW_COPY_AND_ASSIGN(MessageParser);
-};
-
-
-// Class which represents a debug command message and handles it.
-class DbgMessage {
- public:
- DbgMessage(int32_t cmd_idx, const char* start,
- const char* end, intptr_t debug_fd)
- : next_(NULL), cmd_idx_(cmd_idx),
- buffer_(NULL), buffer_len_(end - start),
- debug_fd_(debug_fd) {
- buffer_ = reinterpret_cast<char*>(malloc(buffer_len_));
- ASSERT(buffer_ != NULL);
- memmove(buffer_, start, buffer_len_);
- }
- ~DbgMessage() {
- next_ = NULL;
- free(buffer_);
- }
-
- // Accessors.
- DbgMessage* next() const { return next_; }
- void set_next(DbgMessage* next) { next_ = next; }
- char* buffer() const { return buffer_; }
- int32_t buffer_len() const { return buffer_len_; }
- intptr_t debug_fd() const { return debug_fd_; }
-
- // Handle debugger command message.
- // Returns true if the execution needs to resume after this message is
- // handled, false otherwise.
- bool HandleMessage();
-
- // Send reply after successful handling of command.
- void SendReply(dart::TextBuffer* msg);
-
- // Reply error returned by the command handler.
- void SendErrorReply(int msg_id, const char* err_msg);
-
- // Handlers for specific commands, they are static because these
- // functions are populated as function pointers into a dispatch table.
- static bool HandleResumeCmd(DbgMessage* msg);
- static bool HandleStepIntoCmd(DbgMessage* msg);
- static bool HandleStepOverCmd(DbgMessage* msg);
- static bool HandleStepOutCmd(DbgMessage* msg);
- static bool HandleGetLibrariesCmd(DbgMessage* msg);
- static bool HandleGetClassPropsCmd(DbgMessage* msg);
- static bool HandleGetLibPropsCmd(DbgMessage* msg);
- static bool HandleSetLibPropsCmd(DbgMessage* msg);
- static bool HandleGetGlobalsCmd(DbgMessage* msg);
- static bool HandleEvaluateExprCmd(DbgMessage* msg);
- static bool HandleGetObjPropsCmd(DbgMessage* msg);
- static bool HandleGetListCmd(DbgMessage* msg);
- static bool HandleGetScriptURLsCmd(DbgMessage* msg);
- static bool HandleGetSourceCmd(DbgMessage* msg);
- static bool HandleGetLineNumbersCmd(DbgMessage* msg);
- static bool HandleGetStackTraceCmd(DbgMessage* msg);
- static bool HandlePauseOnExcCmd(DbgMessage* msg);
- static bool HandleSetBpCmd(DbgMessage* msg);
- static bool HandleRemBpCmd(DbgMessage* msg);
-
- private:
- DbgMessage* next_; // Next message in the queue.
- int32_t cmd_idx_; // Isolate specific debugger command index.
- char* buffer_; // Debugger command message.
- int32_t buffer_len_; // Length of the debugger command message.
- intptr_t debug_fd_; // Debugger connection on which replies are to be sent.
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMessage);
-};
-
-
-// Class which represents a queue of debug command messages sent to an isolate.
-class DbgMsgQueue {
- public:
- DbgMsgQueue(Dart_IsolateId isolate_id, DbgMsgQueue* next)
- : is_running_(true),
- is_interrupted_(false),
- msglist_head_(NULL),
- msglist_tail_(NULL),
- queued_output_messages_(64),
- isolate_id_(isolate_id),
- next_(next) {
- }
- ~DbgMsgQueue() {
- DbgMessage* msg = msglist_head_;
- while (msglist_head_ != NULL) {
- msglist_head_ = msglist_head_->next();
- delete msg;
- msg = msglist_head_;
- }
- msglist_tail_ = NULL;
- isolate_id_ = ILLEGAL_ISOLATE_ID;
- next_ = NULL;
- }
-
- // Accessors.
- Dart_IsolateId isolate_id() const { return isolate_id_; }
- DbgMsgQueue* next() const { return next_; }
- void set_next(DbgMsgQueue* next) { next_ = next; }
-
- // Add specified debug command message to the queue.
- void AddMessage(int32_t cmd_idx,
- const char* start,
- const char* end,
- intptr_t debug_fd);
-
- // Notify an isolate of a pending vmservice message.
- void Notify();
-
- // Run a message loop which handles messages as they arrive until
- // normal program execution resumes.
- void MessageLoop();
-
- // Handle any pending debug command messages in the queue. Return
- // value indicates whether a resume has been requested.
- bool HandlePendingMessages();
-
- // Interrupt Isolate.
- void InterruptIsolate();
-
- // Queue output messages, these are sent out when we hit an event.
- void QueueOutputMsg(dart::TextBuffer* msg);
-
- // Send all queued messages over to the debugger.
- void SendQueuedMsgs();
-
- // Send breakpoint event message over to the debugger.
- void SendBreakpointEvent(intptr_t bp_id, const Dart_CodeLocation& location);
-
- // Send Exception event message over to the debugger.
- void SendExceptionEvent(Dart_Handle exception, Dart_StackTrace trace);
-
- // Send Isolate event message over to the debugger.
- void SendIsolateEvent(Dart_IsolateId isolate_id, Dart_IsolateEvent kind);
-
- private:
- bool is_running_; // True if isolate is running and not in the debugger loop.
- bool is_interrupted_; // True if interrupt command is pending.
-
- DbgMessage* msglist_head_; // Start of debugger messages list.
- DbgMessage* msglist_tail_; // End of debugger messages list.
-
- // Text buffer that accumulates messages to be output.
- dart::TextBuffer queued_output_messages_;
-
- Dart_IsolateId isolate_id_; // Id of the isolate tied to this queue.
-
- DbgMsgQueue* next_; // Used for creating a list of message queues.
-
- // The isolate waits on this condition variable when it needs to process
- // debug messages.
- Monitor msg_queue_lock_;
-
- DISALLOW_COPY_AND_ASSIGN(DbgMsgQueue);
-};
-
-
-// Maintains a list of message queues.
-class DbgMsgQueueList {
- public:
- static const int32_t kInvalidCommand = -1;
-
- // Initialize the message queue processing by setting up the appropriate
- // handlers.
- static void Initialize();
-
- // Parses the input message and returns the command index if the message
- // contains a valid isolate specific command.
- // It returns kInvalidCommand otherwise.
- static int32_t LookupIsolateCommand(const char* buf, int32_t buflen);
-
- // Queue debugger message targetted for the isolate.
- static bool AddIsolateMessage(Dart_IsolateId isolate_id,
- int32_t cmd_idx,
- const char* start,
- const char* end,
- intptr_t debug_fd);
-
- // Notify an isolate of a pending vmservice message.
- static void NotifyIsolate(Dart_Isolate isolate);
-
- // Interrupt isolate.
- static bool InterruptIsolate(Dart_IsolateId isolate_id);
-
- // Add Debugger Message Queue corresponding to the Isolate.
- static DbgMsgQueue* AddIsolateMsgQueue(Dart_IsolateId isolate_id);
-
- // Get Debugger Message Queue corresponding to the Isolate.
- static DbgMsgQueue* GetIsolateMsgQueue(Dart_IsolateId isolate_id);
-
- // Remove Debugger Message Queue corresponding to the Isolate.
- static void RemoveIsolateMsgQueue(Dart_IsolateId isolate_id);
-
- // Generic handlers for breakpoints, exceptions and delayed breakpoint
- // resolution.
- static void BptResolvedHandler(Dart_IsolateId isolate_id,
- intptr_t bp_id,
- const Dart_CodeLocation& location);
- static void PausedEventHandler(Dart_IsolateId isolate_id,
- intptr_t bp_id,
- const Dart_CodeLocation& loc);
- static void ExceptionThrownHandler(Dart_IsolateId isolate_id,
- Dart_Handle exception,
- Dart_StackTrace stack_trace);
- static void IsolateEventHandler(Dart_IsolateId isolate_id,
- Dart_IsolateEvent kind);
-
- // Print list of isolate ids of all message queues into text buffer.
- static void ListIsolateIds(dart::TextBuffer* msg);
-
- private:
- static DbgMsgQueue* GetIsolateMsgQueueLocked(Dart_IsolateId isolate_id);
-
- static DbgMsgQueue* list_;
- static Mutex* msg_queue_list_lock_;
-
- DISALLOW_ALLOCATION();
- DISALLOW_IMPLICIT_CONSTRUCTORS(DbgMsgQueueList);
-};
-
-} // namespace bin
-} // namespace dart
-
-#endif // BIN_DBG_MESSAGE_H_
diff --git a/runtime/bin/embedded_dart_io.h b/runtime/bin/embedded_dart_io.h
index e19b21a..4d7dbae 100644
--- a/runtime/bin/embedded_dart_io.h
+++ b/runtime/bin/embedded_dart_io.h
@@ -11,6 +11,19 @@
// Bootstraps 'dart:io'.
void BootstrapDartIo();
+// Tells the system whether to capture Stdout events.
+void SetCaptureStdout(bool value);
+
+// Tells the system whether to capture Stderr events.
+void SetCaptureStderr(bool value);
+
+// Should Stdout events be captured?
+bool ShouldCaptureStdout();
+
+// Should Stderr events be captured?
+bool ShouldCaptureStderr();
+
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/eventhandler_macos.cc b/runtime/bin/eventhandler_macos.cc
index fa2dbf6..edd0485 100644
--- a/runtime/bin/eventhandler_macos.cc
+++ b/runtime/bin/eventhandler_macos.cc
@@ -132,7 +132,7 @@
if (status == -1) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
FATAL1("Failed adding interrupt fd to kqueue: %s\n", error_message);
}
}
@@ -358,7 +358,7 @@
if ((events[i].flags & EV_ERROR) != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(events[i].data, error_message, kBufferSize);
+ Utils::StrError(events[i].data, error_message, kBufferSize);
FATAL1("kevent failed %s\n", error_message);
}
if (events[i].udata == NULL) {
@@ -440,7 +440,7 @@
if (result == -1) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
FATAL1("kevent failed %s\n", error_message);
} else {
handler_impl->HandleTimeout();
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index cfd5637..1face6b 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -6,6 +6,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
+#include "bin/embedded_dart_io.h"
#include "bin/io_buffer.h"
#include "bin/utils.h"
@@ -18,13 +19,31 @@
static const int kMSPerSecond = 1000;
// Are we capturing output from stdout for the VM service?
-bool File::capture_stdout_ = false;
+static bool capture_stdout = false;
// Are we capturing output from stderr for the VM service?
-bool File::capture_stderr_ = false;
+static bool capture_stderr = false;
-// Are we capturing output from either stdout or stderr for the VM Service?
-bool File::capture_any_ = false;
+
+void SetCaptureStdout(bool value) {
+ capture_stdout = value;
+}
+
+
+void SetCaptureStderr(bool value) {
+ capture_stderr = value;
+}
+
+
+bool ShouldCaptureStdout() {
+ return capture_stdout;
+}
+
+
+bool ShouldCaptureStderr() {
+ return capture_stderr;
+}
+
// The file pointer has been passed into Dart as an intptr_t and it is safe
@@ -62,13 +81,13 @@
remaining -= bytes_written; // Reduce the number of remaining bytes.
current_buffer += bytes_written; // Move the buffer forward.
}
- if (capture_any_) {
+ if (capture_stdout || capture_stderr) {
intptr_t fd = GetFD();
- if (fd == STDOUT_FILENO && capture_stdout_) {
+ if (fd == STDOUT_FILENO && capture_stdout) {
Dart_ServiceSendDataEvent("Stdout", "WriteEvent",
reinterpret_cast<const uint8_t*>(buffer),
num_bytes);
- } else if (fd == STDERR_FILENO && capture_stderr_) {
+ } else if (fd == STDERR_FILENO && capture_stderr) {
Dart_ServiceSendDataEvent("Stderr", "WriteEvent",
reinterpret_cast<const uint8_t*>(buffer),
num_bytes);
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 28e85e3..633c006 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -187,18 +187,6 @@
static CObject* StatRequest(const CObjectArray& request);
static CObject* LockRequest(const CObjectArray& request);
- static void set_capture_stdout(bool value) {
- capture_stdout_ = value;
- capture_any_ = (capture_stdout_ || capture_stderr_);
- }
- static bool capture_stdout() { return capture_stdout_; }
-
- static void set_capture_stderr(bool value) {
- capture_stderr_ = value;
- capture_any_ = (capture_stdout_ || capture_stderr_);
- }
- static bool capture_stderr() { return capture_stderr_; }
-
private:
explicit File(FileHandle* handle) : handle_(handle) { }
void Close();
@@ -208,10 +196,6 @@
// FileHandle is an OS specific class which stores data about the file.
FileHandle* handle_; // OS specific handle for the file.
- static bool capture_stdout_;
- static bool capture_stderr_;
- static bool capture_any_;
-
DISALLOW_COPY_AND_ASSIGN(File);
};
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 35b6388..cc29740 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -19,6 +19,7 @@
#include "bin/log.h"
#include "platform/signal_blocker.h"
+#include "platform/utils.h"
namespace dart {
@@ -57,7 +58,7 @@
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
Log::PrintErr("%s\n", error_message);
}
}
@@ -422,7 +423,7 @@
if (result == -1) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
FATAL2("Failed stat on file descriptor %d: %s", fd, error_message);
}
if (S_ISCHR(buf.st_mode)) return kTerminal;
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index ff801ad..d289c21 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -15,9 +15,10 @@
#include <unistd.h> // NOLINT
#include <libgen.h> // NOLINT
-#include "platform/signal_blocker.h"
#include "bin/builtin.h"
#include "bin/log.h"
+#include "platform/signal_blocker.h"
+#include "platform/utils.h"
namespace dart {
@@ -56,7 +57,7 @@
if (err != 0) {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
- Log::PrintErr("%s\n", strerror_r(errno, error_buf, kBufferSize));
+ Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize));
}
}
handle_->set_fd(kClosedFd);
@@ -429,7 +430,7 @@
const int kBufferSize = 1024;
char error_buf[kBufferSize];
FATAL2("Failed stat on file descriptor %d: %s", fd,
- strerror_r(errno, error_buf, kBufferSize));
+ Utils::StrError(errno, error_buf, kBufferSize));
}
if (S_ISCHR(buf.st_mode)) return kTerminal;
if (S_ISFIFO(buf.st_mode)) return kPipe;
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index ddc19cc..6187e94 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -20,6 +20,7 @@
#include "bin/log.h"
#include "platform/signal_blocker.h"
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -57,7 +58,7 @@
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
Log::PrintErr("%s\n", error_message);
}
}
@@ -394,7 +395,7 @@
if (result == -1) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
FATAL2("Failed stat on file descriptor %d: %s", fd, error_message);
}
if (S_ISCHR(buf.st_mode)) return kTerminal;
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 72c5460..29485e2 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -11,8 +11,8 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
#include "bin/directory.h"
+#include "bin/embedded_dart_io.h"
#include "bin/eventhandler.h"
#include "bin/extensions.h"
#include "bin/file.h"
@@ -21,9 +21,11 @@
#include "bin/platform.h"
#include "bin/process.h"
#include "bin/thread.h"
+#include "bin/utils.h"
#include "bin/vmservice_impl.h"
#include "platform/globals.h"
#include "platform/hashmap.h"
+#include "platform/text_buffer.h"
namespace dart {
namespace bin {
@@ -42,20 +44,6 @@
static const char* snapshot_filename = NULL;
-// Global state that indicates whether there is a debug breakpoint.
-// This pointer points into an argv buffer and does not need to be
-// free'd.
-static const char* breakpoint_at = NULL;
-
-
-// Global state that indicates whether we should open a connection
-// and listen for a debugger to connect.
-static bool start_debugger = false;
-static const char* debug_ip = NULL;
-static int debug_port = -1;
-static const char* DEFAULT_DEBUG_IP = "127.0.0.1";
-static const int DEFAULT_DEBUG_PORT = 5858;
-
// Value of the --package-root flag.
// (This pointer points into an argv buffer and does not need to be
// free'd.)
@@ -142,7 +130,6 @@
}
if (do_vm_shutdown) {
- DebuggerConnectionHandler::StopHandler();
EventHandler::Stop();
}
Platform::Exit(exit_code);
@@ -193,17 +180,6 @@
}
-static bool ProcessBreakpointOption(const char* funcname,
- CommandLineOptions* vm_options) {
- ASSERT(funcname != NULL);
- if (*funcname == '\0') {
- return false;
- }
- breakpoint_at = funcname;
- return true;
-}
-
-
static bool ProcessPackageRootOption(const char* arg,
CommandLineOptions* vm_options) {
ASSERT(arg != NULL);
@@ -369,22 +345,6 @@
}
-static bool ProcessDebugOption(const char* option_value,
- CommandLineOptions* vm_options) {
- ASSERT(option_value != NULL);
- if (!ExtractPortAndIP(option_value, &debug_port, &debug_ip,
- DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_IP)) {
- Log::PrintErr("unrecognized --debug option syntax. "
- "Use --debug[:<port number>[/<IPv4 address>]]\n");
- return false;
- }
-
- breakpoint_at = "main";
- start_debugger = true;
- return true;
-}
-
-
static bool ProcessScriptSnapshotOptionHelper(const char* filename,
bool* snapshot_option) {
*snapshot_option = false;
@@ -458,17 +418,6 @@
}
-extern bool trace_debug_protocol;
-static bool ProcessTraceDebugProtocolOption(const char* arg,
- CommandLineOptions* vm_options) {
- if (*arg != '\0') {
- return false;
- }
- trace_debug_protocol = true;
- return true;
-}
-
-
static bool ProcessTraceLoadingOption(const char* arg,
CommandLineOptions* vm_options) {
if (*arg != '\0') {
@@ -522,9 +471,7 @@
{ "--version", ProcessVersionOption },
// VM specific options to the standalone dart program.
- { "--break-at=", ProcessBreakpointOption },
{ "--compile_all", ProcessCompileAllOption },
- { "--debug", ProcessDebugOption },
{ "--enable-vm-service", ProcessEnableVmServiceOption },
{ "--gen-precompiled-snapshot", ProcessGenPrecompiledSnapshotOption },
{ "--noopt", ProcessNooptOption },
@@ -533,7 +480,6 @@
{ "--shutdown", ProcessShutdownOption },
{ "--snapshot=", ProcessScriptSnapshotOption },
{ "--snapshot-after-run=", ProcessScriptSnapshotAfterRunOption },
- { "--trace-debug-protocol", ProcessTraceDebugProtocolOption },
{ "--trace-loading", ProcessTraceLoadingOption },
{ NULL, NULL }
};
@@ -963,25 +909,6 @@
}
-static Dart_Handle SetBreakpoint(const char* breakpoint_at,
- Dart_Handle library) {
- char* bpt_function = strdup(breakpoint_at);
- Dart_Handle class_name;
- Dart_Handle function_name;
- char* dot = strchr(bpt_function, '.');
- if (dot == NULL) {
- class_name = DartUtils::NewString("");
- function_name = DartUtils::NewString(breakpoint_at);
- } else {
- *dot = '\0';
- class_name = DartUtils::NewString(bpt_function);
- function_name = DartUtils::NewString(dot + 1);
- }
- free(bpt_function);
- return Dart_OneTimeBreakAtEntry(library, class_name, function_name);
-}
-
-
char* BuildIsolateName(const char* script_name,
const char* func_name) {
// Skip past any slashes in the script name.
@@ -1028,14 +955,21 @@
DartScope scope;
// TODO(ajohnsen): Store the library/function in isolate data or user_data.
Dart_Handle dart_io_str = Dart_NewStringFromCString("dart:io");
- if (Dart_IsError(dart_io_str)) return ServiceRequestError(dart_io_str);
+ if (Dart_IsError(dart_io_str)) {
+ return ServiceRequestError(dart_io_str);
+ }
+
Dart_Handle io_lib = Dart_LookupLibrary(dart_io_str);
- if (Dart_IsError(io_lib)) return ServiceRequestError(io_lib);
+ if (Dart_IsError(io_lib)) {
+ return ServiceRequestError(io_lib);
+ }
+
Dart_Handle handler_function_name =
Dart_NewStringFromCString("_serviceObjectHandler");
if (Dart_IsError(handler_function_name)) {
return ServiceRequestError(handler_function_name);
}
+
// TODO(johnmccutchan): paths is no longer used. Update the io
// _serviceObjectHandler function to use json rpc.
Dart_Handle paths = Dart_NewList(0);
@@ -1047,10 +981,15 @@
}
Dart_Handle args[] = {paths, keys, values};
Dart_Handle result = Dart_Invoke(io_lib, handler_function_name, 3, args);
- if (Dart_IsError(result)) return ServiceRequestError(result);
+ if (Dart_IsError(result)) {
+ return ServiceRequestError(result);
+ }
+
const char *json;
result = Dart_StringToCString(result, &json);
- if (Dart_IsError(result)) return ServiceRequestError(result);
+ if (Dart_IsError(result)) {
+ return ServiceRequestError(result);
+ }
return strdup(json);
}
@@ -1061,10 +1000,10 @@
static bool ServiceStreamListenCallback(const char* stream_id) {
if (strcmp(stream_id, kStdoutStreamId) == 0) {
- File::set_capture_stdout(true);
+ SetCaptureStdout(true);
return true;
} else if (strcmp(stream_id, kStderrStreamId) == 0) {
- File::set_capture_stderr(true);
+ SetCaptureStderr(true);
return true;
}
return false;
@@ -1073,9 +1012,9 @@
static void ServiceStreamCancelCallback(const char* stream_id) {
if (strcmp(stream_id, kStdoutStreamId) == 0) {
- File::set_capture_stdout(false);
+ SetCaptureStdout(false);
} else if (strcmp(stream_id, kStderrStreamId) == 0) {
- File::set_capture_stderr(false);
+ SetCaptureStderr(false);
}
}
@@ -1198,7 +1137,6 @@
free(error);
}
if (do_vm_shutdown) {
- DebuggerConnectionHandler::StopHandler();
EventHandler::Stop();
}
Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
@@ -1315,18 +1253,6 @@
Dart_NewStringFromCString("_getMainClosure"), 0, NULL);
CHECK_RESULT(main_closure);
- // Set debug breakpoint if specified on the command line before calling
- // the main function.
- if (breakpoint_at != NULL) {
- result = SetBreakpoint(breakpoint_at, root_lib);
- if (Dart_IsError(result)) {
- ErrorExit(kErrorExitCode,
- "Error setting breakpoint at '%s': %s\n",
- breakpoint_at,
- Dart_GetError(result));
- }
- }
-
// Call _startIsolate in the isolate library to enable dispatching the
// initial startup message.
const intptr_t kNumIsolateArgs = 2;
@@ -1433,18 +1359,6 @@
// Start event handler.
EventHandler::Start();
- // Start the debugger wire protocol handler if necessary.
- if (start_debugger) {
- ASSERT(debug_port >= 0);
- bool print_msg = verbose_debug_seen || (debug_port == 0);
- debug_port = DebuggerConnectionHandler::StartHandler(debug_ip, debug_port);
- if (print_msg) {
- Log::Print("Debugger listening on port %d\n", debug_port);
- }
- } else {
- DebuggerConnectionHandler::InitForVmService();
- }
-
const uint8_t* instructions_snapshot = NULL;
if (has_run_precompiled_snapshot) {
instructions_snapshot = reinterpret_cast<const uint8_t*>(
@@ -1465,7 +1379,6 @@
GetVMServiceAssetsArchiveCallback);
if (error != NULL) {
if (do_vm_shutdown) {
- DebuggerConnectionHandler::StopHandler();
EventHandler::Stop();
}
fprintf(stderr, "VM initialization failed: %s\n", error);
@@ -1493,7 +1406,6 @@
free(error);
}
if (do_vm_shutdown) {
- DebuggerConnectionHandler::StopHandler();
EventHandler::Stop();
}
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index 8188693..f9d3457 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
#include "bin/dartutils.h"
-#include "bin/dbg_connection.h"
-#include "bin/eventhandler.h"
#include "bin/io_buffer.h"
#include "bin/log.h"
#include "bin/platform.h"
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 9265531..b9d245b 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -22,6 +22,7 @@
#include "bin/thread.h"
#include "platform/signal_blocker.h"
+#include "platform/utils.h"
extern char **environ;
@@ -644,7 +645,7 @@
void SetChildOsErrorMessage() {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
*os_error_message_ = strdup(error_message);
}
@@ -655,7 +656,7 @@
int child_errno = errno;
const int kBufferSize = 1024;
char os_error_message[kBufferSize];
- strerror_r(errno, os_error_message, kBufferSize);
+ Utils::StrError(errno, os_error_message, kBufferSize);
int bytes_written =
FDUtils::WriteToBlocking(
exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index cd9c639..30f188f 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -16,11 +16,12 @@
#include <sys/wait.h> // NOLINT
#include <unistd.h> // NOLINT
-#include "platform/signal_blocker.h"
#include "bin/fdutils.h"
#include "bin/lockers.h"
#include "bin/log.h"
#include "bin/thread.h"
+#include "platform/signal_blocker.h"
+#include "platform/utils.h"
extern char **environ;
@@ -643,7 +644,7 @@
void SetChildOsErrorMessage() {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
- *os_error_message_ = strdup(strerror_r(errno, error_buf, kBufferSize));
+ *os_error_message_ = strdup(Utils::StrError(errno, error_buf, kBufferSize));
}
@@ -653,7 +654,7 @@
int child_errno = errno;
const int kBufferSize = 1024;
char error_buf[kBufferSize];
- char* os_error_message = strerror_r(errno, error_buf, kBufferSize);
+ char* os_error_message = Utils::StrError(errno, error_buf, kBufferSize);
int bytes_written =
FDUtils::WriteToBlocking(
exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index f694958..1ce34f9 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -25,6 +25,7 @@
#include "bin/thread.h"
#include "platform/signal_blocker.h"
+#include "platform/utils.h"
@@ -660,7 +661,7 @@
void SetChildOsErrorMessage() {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
*os_error_message_ = strdup(error_message);
}
@@ -671,7 +672,7 @@
int child_errno = errno;
const int kBufferSize = 1024;
char os_error_message[kBufferSize];
- strerror_r(errno, os_error_message, kBufferSize);
+ Utils::StrError(errno, os_error_message, kBufferSize);
int bytes_written =
FDUtils::WriteToBlocking(
exec_control_[1], &child_errno, sizeof(child_errno));
diff --git a/runtime/bin/run_vm_tests.cc b/runtime/bin/run_vm_tests.cc
index 19ef7e9b..bfb597b 100644
--- a/runtime/bin/run_vm_tests.cc
+++ b/runtime/bin/run_vm_tests.cc
@@ -107,7 +107,7 @@
ASSERT(set_vm_flags_success);
const char* err_msg = Dart::InitOnce(dart::bin::vm_isolate_snapshot_buffer,
NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL,
dart::bin::DartUtils::OpenFile,
dart::bin::DartUtils::ReadFile,
dart::bin::DartUtils::WriteFile,
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index 60dc75f2..d4a67bc 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -33,8 +33,8 @@
class Thread {
public:
- static ThreadLocalKey kUnsetThreadLocalKey;
- static ThreadId kInvalidThreadId;
+ static const ThreadLocalKey kUnsetThreadLocalKey;
+ static const ThreadId kInvalidThreadId;
typedef void (*ThreadStartFunction) (uword parameter);
diff --git a/runtime/bin/thread_android.cc b/runtime/bin/thread_android.cc
index 62143ef..f84a988 100644
--- a/runtime/bin/thread_android.cc
+++ b/runtime/bin/thread_android.cc
@@ -11,6 +11,7 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -19,7 +20,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}
@@ -29,7 +30,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, error_message); \
return result; \
@@ -113,8 +114,9 @@
}
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_linux.cc b/runtime/bin/thread_linux.cc
index eaa4f2a..1e01a77 100644
--- a/runtime/bin/thread_linux.cc
+++ b/runtime/bin/thread_linux.cc
@@ -12,6 +12,7 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -21,7 +22,7 @@
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
FATAL2("pthread error: %d (%s)", result, \
- strerror_r(result, error_buf, kBufferSize)); \
+ Utils::StrError(result, error_buf, kBufferSize)); \
}
@@ -32,7 +33,7 @@
char error_buf[kBufferSize]; \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, \
- strerror_r(result, error_buf, kBufferSize)); \
+ Utils::StrError(result, error_buf, kBufferSize)); \
return result; \
}
#else
@@ -114,8 +115,9 @@
}
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_macos.cc b/runtime/bin/thread_macos.cc
index 52ac76c..28c747d 100644
--- a/runtime/bin/thread_macos.cc
+++ b/runtime/bin/thread_macos.cc
@@ -19,6 +19,7 @@
#include <mach/thread_act.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
namespace bin {
@@ -27,7 +28,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}
@@ -37,7 +38,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, error_message); \
return result; \
@@ -106,8 +107,9 @@
}
-ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/bin/thread_win.cc b/runtime/bin/thread_win.cc
index 05949a1..44941bb 100644
--- a/runtime/bin/thread_win.cc
+++ b/runtime/bin/thread_win.cc
@@ -70,8 +70,8 @@
return 0;
}
-ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-ThreadId Thread::kInvalidThreadId = 0;
+const ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
+const ThreadId Thread::kInvalidThreadId = 0;
ThreadLocalKey Thread::CreateThreadLocal() {
ThreadLocalKey key = TlsAlloc();
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index 00cf93d..d96eb5d 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -12,6 +12,7 @@
#include "bin/utils.h"
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
@@ -22,7 +23,7 @@
set_code(errno);
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
SetMessage(error_message);
}
@@ -33,7 +34,7 @@
if (sub_system == kSystem) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(code, error_message, kBufferSize);
+ Utils::StrError(code, error_message, kBufferSize);
SetMessage(error_message);
} else if (sub_system == kGetAddressInfo) {
SetMessage(gai_strerror(code));
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index f3d8654..f84ba33 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -12,6 +12,7 @@
#include "bin/utils.h"
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
@@ -22,7 +23,7 @@
set_code(errno);
const int kBufferSize = 1024;
char error_buf[kBufferSize];
- SetMessage(strerror_r(errno, error_buf, kBufferSize));
+ SetMessage(Utils::StrError(errno, error_buf, kBufferSize));
}
@@ -32,7 +33,7 @@
if (sub_system == kSystem) {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
- SetMessage(strerror_r(code, error_buf, kBufferSize));
+ SetMessage(Utils::StrError(code, error_buf, kBufferSize));
} else if (sub_system == kGetAddressInfo) {
SetMessage(gai_strerror(code));
} else {
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index 4004f38..1d792c9 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -12,6 +12,7 @@
#include "bin/utils.h"
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
@@ -22,7 +23,7 @@
set_code(errno);
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(errno, error_message, kBufferSize);
+ Utils::StrError(errno, error_message, kBufferSize);
SetMessage(error_message);
}
@@ -33,7 +34,7 @@
if (sub_system == kSystem) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
- strerror_r(code, error_message, kBufferSize);
+ Utils::StrError(code, error_message, kBufferSize);
SetMessage(error_message);
} else if (sub_system == kGetAddressInfo) {
SetMessage(gai_strerror(code));
diff --git a/runtime/bin/vmservice/loader.dart b/runtime/bin/vmservice/loader.dart
index cd94f57..38b62b1 100644
--- a/runtime/bin/vmservice/loader.dart
+++ b/runtime/bin/vmservice/loader.dart
@@ -62,32 +62,16 @@
});
}
-var dataUriRegex = new RegExp(
- r"data:([\w-]+/[\w-]+)?(;charset=([\w-]+))?(;base64)?,(.*)");
-
void _loadDataUri(SendPort sp, int id, Uri uri) {
try {
- var match = dataUriRegex.firstMatch(uri.toString());
- if (match == null) throw "Malformed data uri";
-
- var mimeType = match.group(1);
- var encoding = match.group(3);
- var maybeBase64 = match.group(4);
- var encodedData = match.group(5);
-
- if (mimeType != "application/dart") {
+ if (uri.data.mimeType != "application/dart") {
throw "MIME-type must be application/dart";
}
- if (encoding != "utf-8") {
- // Default is ASCII. The C++ portion of the embedder assumes UTF-8.
+ if (uri.data.charset != "utf-8") {
+ // The C++ portion of the embedder assumes UTF-8.
throw "Only utf-8 encoding is supported";
}
- if (maybeBase64 != null) {
- throw "Only percent encoding is supported";
- }
-
- var data = UTF8.encode(Uri.decodeComponent(encodedData));
- _sendResourceResponse(sp, id, data);
+ _sendResourceResponse(sp, id, uri.data.contentAsBytes());
} catch (e) {
_sendResourceResponse(sp, id, "Invalid data uri ($uri):\n $e");
}
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 1f7eee2..987af55 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -5,6 +5,7 @@
library vmservice_io;
import 'dart:async';
+import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
@@ -27,7 +28,7 @@
// HTTP server.
Server server;
Future<Server> serverFuture;
-Map<String, Asset> assets;
+HashMap<String, Asset> assets;
_onShutdown() {
if (server != null) {
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 2a38c32..f46a66a 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -12,7 +12,7 @@
#include "bin/platform.h"
#include "bin/thread.h"
#include "bin/utils.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
namespace dart {
namespace bin {
@@ -31,8 +31,9 @@
}
#define kLibrarySourceNamePrefix "/vmservice"
-static const char* kVMServiceIOLibraryUri = "dart:vmservice_io";
-static const char* kVMServiceIOLibraryScriptResourceName = "vmservice_io.dart";
+static const char* const kVMServiceIOLibraryUri = "dart:vmservice_io";
+static const char* const kVMServiceIOLibraryScriptResourceName =
+ "vmservice_io.dart";
struct ResourcesEntry {
const char* path_;
diff --git a/runtime/dart-runtime.gyp b/runtime/dart-runtime.gyp
index e5c8805..fd3701e 100644
--- a/runtime/dart-runtime.gyp
+++ b/runtime/dart-runtime.gyp
@@ -55,6 +55,40 @@
},
},
{
+ 'target_name': 'libdart_precompiled',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'libdart_lib',
+ 'libdart_vm_precompiled',
+ 'libdouble_conversion',
+ 'generate_version_cc_file#host',
+ ],
+ 'include_dirs': [
+ '.',
+ ],
+ 'sources': [
+ 'include/dart_api.h',
+ 'include/dart_mirrors_api.h',
+ 'include/dart_native_api.h',
+ 'include/dart_tools_api.h',
+ 'vm/dart_api_impl.cc',
+ 'vm/debugger_api_impl.cc',
+ 'vm/mirrors_api_impl.cc',
+ 'vm/native_api_impl.cc',
+ 'vm/version.h',
+ '<(version_cc_file)',
+ ],
+ 'defines': [
+ # The only effect of DART_SHARED_LIB is to export the Dart API entries.
+ 'DART_SHARED_LIB',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'include',
+ ],
+ },
+ },
+ {
'target_name': 'generate_version_cc_file',
'type': 'none',
'toolsets':['host'],
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 29826af..9666364 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -501,140 +501,6 @@
Dart_Isolate isolate,
Dart_WeakPersistentHandle object);
-/**
- * Allocates a prologue weak persistent handle for an object.
- *
- * Prologue weak persistent handles are similar to weak persistent
- * handles but exhibit different behavior during garbage collections
- * that invoke the prologue and epilogue callbacks. While weak
- * persistent handles always weakly reference their referents,
- * prologue weak persistent handles weakly reference their referents
- * only during a garbage collection that invokes the prologue and
- * epilogue callbacks. During all other garbage collections, prologue
- * weak persistent handles strongly reference their referents.
- *
- * This handle has the lifetime of the current isolate unless the object
- * pointed to by the handle is garbage collected, in this case the VM
- * automatically deletes the handle after invoking the callback associated
- * with the handle. The handle can also be explicitly deallocated by
- * calling Dart_DeleteWeakPersistentHandle.
- *
- * If the object becomes unreachable the callback is invoked with the weak
- * persistent handle and the peer as arguments. This gives the native code the
- * ability to cleanup data associated with the object and clear out any cached
- * references to the handle. All references to this handle after the callback
- * will be invalid. It is illegal to call into the VM from the callback.
- * If the handle is deleted before the object becomes unreachable,
- * the callback is never invoked.
- *
- * Requires there to be a current isolate.
- *
- * \param object An object.
- * \param peer A pointer to a native object or NULL. This value is
- * provided to callback when it is invoked.
- * \param external_allocation_size The number of externally allocated
- * bytes for peer. Used to inform the garbage collector.
- * \param callback A function pointer that will be invoked sometime
- * after the object is garbage collected, unless the handle has been deleted.
- * A valid callback needs to be specified it cannot be NULL.
- *
- * \return Success if the prologue weak persistent handle was created.
- * Otherwise, returns an error.
- */
-DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
- Dart_Handle object,
- void* peer,
- intptr_t external_allocation_size,
- Dart_WeakPersistentHandleFinalizer callback);
-
-/**
- * Is this object a prologue weak persistent handle?
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
- Dart_WeakPersistentHandle object);
-
-typedef struct _Dart_WeakReferenceSetBuilder* Dart_WeakReferenceSetBuilder;
-typedef struct _Dart_WeakReferenceSet* Dart_WeakReferenceSet;
-
-/**
- * Constructs a weak references set builder.
- *
- * \returns a pointer to the weak reference set builder if successful.
- * Otherwise, returns NULL.
- */
-DART_EXPORT Dart_WeakReferenceSetBuilder Dart_NewWeakReferenceSetBuilder();
-
-/**
- * Constructs a set of weak references from the Cartesian product of
- * the objects in the key set and the objects in values set.
- *
- * \param set_builder The weak references set builder which was created
- * using Dart_NewWeakReferenceSetBuilder().
- * \param key An object reference. This references will be
- * considered weak by the garbage collector.
- * \param value An object reference. This reference will be
- * considered weak by garbage collector unless any object reference
- * in 'keys' is found to be strong.
- *
- * \return a pointer to the weak reference set if successful.
- * Otherwise, returns NULL.
- */
-DART_EXPORT Dart_WeakReferenceSet Dart_NewWeakReferenceSet(
- Dart_WeakReferenceSetBuilder set_builder,
- Dart_WeakPersistentHandle key,
- Dart_WeakPersistentHandle value);
-
-/**
- * Append the pair of key/value object references to the weak references set.
- *
- * \param reference_set A weak references set into which the pair of key/value
- * needs to be added.
- * \param key An object reference. This references will be
- * considered weak by the garbage collector.
- * \param value An object reference. This reference will be
- * considered weak by garbage collector unless any object reference
- * in 'keys' is found to be strong.
- *
- * \return Success if the prologue weak persistent handle was created.
- * Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle key,
- Dart_WeakPersistentHandle value);
-
-/**
- * Append the key object reference to the weak references set.
- *
- * \param reference_set A weak references set into which the key
- * needs to be added.
- * \param key An object reference. This references will be
- * considered weak by the garbage collector.
- *
- * \return Success if the prologue weak persistent handle was created.
- * Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendKeyToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle key);
-
-/**
- * Append the value object reference to the weak references set.
- *
- * \param reference_set A weak references set into which the key
- * needs to be added.
- * \param value An object reference. This references will be
- * considered weak by the garbage collector.
- *
- * \return Success if the prologue weak persistent handle was created.
- * Otherwise, returns an error.
- */
-DART_EXPORT Dart_Handle Dart_AppendValueToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle value);
-
/*
* ============================
@@ -785,28 +651,14 @@
/**
* An isolate interrupt callback function.
*
- * This callback, provided by the embedder, is called when an isolate
- * is interrupted as a result of a call to Dart_InterruptIsolate().
- * When the callback is called, Dart_CurrentIsolate can be used to
- * figure out which isolate is being interrupted.
- *
- * \return The embedder returns true if the isolate should continue
- * execution. If the embedder returns false, the isolate will be
- * unwound (currently unimplemented).
+ * This callback has been DEPRECATED.
*/
typedef bool (*Dart_IsolateInterruptCallback)();
-/* TODO(turnidge): Define and implement unwinding. */
/**
* An isolate unhandled exception callback function.
*
- * This callback, provided by the embedder, is called when an unhandled
- * exception or internal error is thrown during isolate execution. When the
- * callback is invoked, Dart_CurrentIsolate can be used to figure out which
- * isolate was running when the exception was thrown.
- *
- * \param error The unhandled exception or error. This handle's scope is
- * only valid until the embedder returns from this callback.
+ * This callback has been DEPRECATED.
*/
typedef void (*Dart_IsolateUnhandledExceptionCallback)(Dart_Handle error);
@@ -888,10 +740,8 @@
* instructions, or NULL if no snapshot is provided.
* \param create A function to be called during isolate creation.
* See Dart_IsolateCreateCallback.
- * \param interrupt A function to be called when an isolate is interrupted.
- * See Dart_IsolateInterruptCallback.
- * \param unhandled_exception A function to be called if an isolate has an
- * unhandled exception. Set Dart_IsolateUnhandledExceptionCallback.
+ * \param interrupt This parameter has been DEPRECATED.
+ * \param unhandled_exception This parameter has been DEPRECATED.
* \param shutdown A function to be called when an isolate is shutdown.
* See Dart_IsolateShutdownCallback.
*
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 79749fd..224d532 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -73,3 +73,7 @@
}
}
}
+
+patch class StackTrace {
+ /* patch */ static StackTrace get current native "StackTrace_current";
+}
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 00efcae..dc52798 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -24,6 +24,9 @@
namespace dart {
+DEFINE_FLAG(bool, i_like_slow_isolate_spawn, false,
+ "Block the parent thread when loading spawned isolates.");
+
static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
return reinterpret_cast<uint8_t*>(new_ptr);
@@ -217,16 +220,28 @@
Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
- Dart::thread_pool()->Run(new SpawnIsolateTask(
- new IsolateSpawnState(port.Id(),
- isolate->origin_id(),
- isolate->init_callback_data(),
- func,
- message,
- paused.value(),
- fatal_errors,
- on_exit_port,
- on_error_port)));
+ ThreadPool::Task* spawn_task =
+ new SpawnIsolateTask(
+ new IsolateSpawnState(port.Id(),
+ isolate->origin_id(),
+ isolate->init_callback_data(),
+ func,
+ message,
+ paused.value(),
+ fatal_errors,
+ on_exit_port,
+ on_error_port));
+ if (FLAG_i_like_slow_isolate_spawn) {
+ // We block the parent isolate while the child isolate loads.
+ Isolate* saved = Isolate::Current();
+ Thread::ExitIsolate();
+ spawn_task->Run();
+ delete spawn_task;
+ spawn_task = NULL;
+ Thread::EnterIsolate(saved);
+ } else {
+ Dart::thread_pool()->Run(spawn_task);
+ }
return Object::null();
}
}
@@ -258,8 +273,8 @@
if (handler != NULL) {
Dart_EnterScope();
Dart_Handle handle = handler(Dart_kCanonicalizeUrl,
- Api::NewHandle(isolate, library.raw()),
- Api::NewHandle(isolate, uri.raw()));
+ Api::NewHandle(thread, library.raw()),
+ Api::NewHandle(thread, uri.raw()));
const Object& obj = Object::Handle(Api::UnwrapHandle(handle));
if (obj.IsString()) {
result = String2UTF8(String::Cast(obj));
@@ -302,6 +317,13 @@
GET_NATIVE_ARGUMENT(String, package_root, arguments->NativeArgAt(10));
GET_NATIVE_ARGUMENT(Array, packages, arguments->NativeArgAt(11));
+ if (Dart::IsRunningPrecompiledCode()) {
+ const Array& args = Array::Handle(Array::New(1));
+ args.SetAt(0, String::Handle(String::New(
+ "Isolate.spawnUri not supported under precompilation")));
+ Exceptions::ThrowByType(Exceptions::kUnsupported, args);
+ UNREACHABLE();
+ }
// Canonicalize the uri with respect to the current isolate.
const Library& root_lib =
@@ -339,25 +361,38 @@
Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
- IsolateSpawnState* state = new IsolateSpawnState(
- port.Id(),
- isolate->init_callback_data(),
- canonical_uri,
- utf8_package_root,
- const_cast<const char**>(utf8_package_map),
- args,
- message,
- paused.value(),
- fatal_errors,
- on_exit_port,
- on_error_port);
+ IsolateSpawnState* state =
+ new IsolateSpawnState(
+ port.Id(),
+ isolate->init_callback_data(),
+ canonical_uri,
+ utf8_package_root,
+ const_cast<const char**>(utf8_package_map),
+ args,
+ message,
+ paused.value(),
+ fatal_errors,
+ on_exit_port,
+ on_error_port);
+
// If we were passed a value then override the default flags state for
// checked mode.
if (!checked.IsNull()) {
state->isolate_flags()->set_checked(checked.value());
}
- Dart::thread_pool()->Run(new SpawnIsolateTask(state));
+ ThreadPool::Task* spawn_task = new SpawnIsolateTask(state);
+ if (FLAG_i_like_slow_isolate_spawn) {
+ // We block the parent isolate while the child isolate loads.
+ Isolate* saved = Isolate::Current();
+ Thread::ExitIsolate();
+ spawn_task->Run();
+ delete spawn_task;
+ spawn_task = NULL;
+ Thread::EnterIsolate(saved);
+ } else {
+ Dart::thread_pool()->Run(spawn_task);
+ }
return Object::null();
}
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 4b8627f..53af2c4 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -2024,8 +2024,7 @@
token_pos = cls.token_pos();
} else if (decl.IsField()) {
const Field& field = Field::Cast(decl);
- const Class& owner = Class::Handle(field.owner());
- script = owner.script();
+ script = field.script();
token_pos = field.token_pos();
} else if (decl.IsTypeParameter()) {
const TypeParameter& type_var = TypeParameter::Cast(decl);
diff --git a/runtime/lib/stacktrace.cc b/runtime/lib/stacktrace.cc
index 6175b24..7b79314 100644
--- a/runtime/lib/stacktrace.cc
+++ b/runtime/lib/stacktrace.cc
@@ -11,7 +11,8 @@
namespace dart {
static void IterateFrames(const GrowableObjectArray& code_list,
- const GrowableObjectArray& pc_offset_list) {
+ const GrowableObjectArray& pc_offset_list,
+ int skip_frames) {
StackFrameIterator frames(StackFrameIterator::kDontValidateFrames);
StackFrame* frame = frames.NextFrame();
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
@@ -19,15 +20,35 @@
Smi& offset = Smi::Handle();
while (frame != NULL) {
if (frame->IsDartFrame()) {
- code = frame->LookupDartCode();
- offset = Smi::New(frame->pc() - code.EntryPoint());
- code_list.Add(code);
- pc_offset_list.Add(offset);
+ if (skip_frames > 0) {
+ skip_frames--;
+ } else {
+ code = frame->LookupDartCode();
+ offset = Smi::New(frame->pc() - code.EntryPoint());
+ code_list.Add(code);
+ pc_offset_list.Add(offset);
+ }
}
frame = frames.NextFrame();
}
}
+// Creates a Stacktrace object from the current stack.
+//
+// Skips the first skip_frames Dart frames.
+static const Stacktrace& GetCurrentStacktrace(int skip_frames) {
+ const GrowableObjectArray& code_list =
+ GrowableObjectArray::Handle(GrowableObjectArray::New());
+ const GrowableObjectArray& pc_offset_list =
+ GrowableObjectArray::Handle(GrowableObjectArray::New());
+ IterateFrames(code_list, pc_offset_list, skip_frames);
+ const Array& code_array = Array::Handle(Array::MakeArray(code_list));
+ const Array& pc_offset_array =
+ Array::Handle(Array::MakeArray(pc_offset_list));
+ const Stacktrace& stacktrace = Stacktrace::Handle(
+ Stacktrace::New(code_array, pc_offset_array));
+ return stacktrace;
+}
// An utility method for convenient printing of dart stack traces when
// inside 'gdb'. Note: This function will only work when there is a
@@ -35,17 +56,13 @@
// set in dart code and control is got inside 'gdb' without going through
// the runtime or native transition stub.
void _printCurrentStacktrace() {
- const GrowableObjectArray& code_list =
- GrowableObjectArray::Handle(GrowableObjectArray::New());
- const GrowableObjectArray& pc_offset_list =
- GrowableObjectArray::Handle(GrowableObjectArray::New());
- IterateFrames(code_list, pc_offset_list);
- const Array& code_array = Array::Handle(Array::MakeArray(code_list));
- const Array& pc_offset_array =
- Array::Handle(Array::MakeArray(pc_offset_list));
- const Stacktrace& stacktrace = Stacktrace::Handle(
- Stacktrace::New(code_array, pc_offset_array));
+ const Stacktrace& stacktrace = GetCurrentStacktrace(0);
OS::PrintErr("=== Current Trace:\n%s===\n", stacktrace.ToCString());
}
+DEFINE_NATIVE_ENTRY(StackTrace_current, 0) {
+ const Stacktrace& stacktrace = GetCurrentStacktrace(1);
+ return stacktrace.raw();
+}
+
} // namespace dart
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index a26c847..39fa28b 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -55,7 +55,9 @@
}
int64_t pid = OS::ProcessId();
- int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
char* json = OS::SCreate(zone,
"{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
@@ -101,7 +103,9 @@
int64_t duration = end.AsInt64Value() - start.AsInt64Value();
int64_t pid = OS::ProcessId();
- int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
char* json = OS::SCreate(zone,
"{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
@@ -144,7 +148,9 @@
}
int64_t pid = OS::ProcessId();
- int64_t tid = OSThread::ThreadIdToIntPtr(OSThread::GetCurrentThreadTraceId());
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ int64_t tid = OSThread::ThreadIdToIntPtr(os_thread->trace_id());
char* json = OS::SCreate(zone,
"{\"name\":\"%s\",\"cat\":\"%s\",\"tid\":%" Pd64 ",\"pid\":%" Pd64 ","
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 12aadb6..83a25e1 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -3,9 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/bootstrap_natives.h"
-
#include "vm/dart_api_impl.h"
+#include "vm/datastream.h"
#include "vm/exceptions.h"
+#include "vm/growable_array.h"
#include "vm/message.h"
#include "vm/native_entry.h"
#include "vm/object.h"
@@ -151,4 +152,245 @@
return Service::RequestAssets();
}
+
+// TODO(25041): When reading, this class copies out the filenames and contents
+// into new buffers. It does this because the lifetime of |bytes| is uncertain.
+// If |bytes| is pinned in memory, then we could instead load up
+// |filenames_| and |contents_| with pointers into |bytes| without making
+// copies.
+class TarArchive {
+ public:
+ TarArchive(uint8_t* bytes, intptr_t bytes_length)
+ : rs_(bytes, bytes_length) {}
+
+ void Read() {
+ while (HasNext()) {
+ char* filename;
+ uint8_t* data;
+ intptr_t data_length;
+ if (Next(&filename, &data, &data_length)) {
+ filenames_.Add(filename);
+ contents_.Add(data);
+ content_lengths_.Add(data_length);
+ }
+ }
+ }
+
+ char* NextFilename() {
+ return filenames_.RemoveLast();
+ }
+
+ uint8_t* NextContent() {
+ return contents_.RemoveLast();
+ }
+
+ intptr_t NextContentLength() {
+ return content_lengths_.RemoveLast();
+ }
+
+ bool HasMore() const {
+ return filenames_.length() > 0;
+ }
+
+ intptr_t Length() const { return filenames_.length(); }
+
+ private:
+ enum TarHeaderFields {
+ kTarHeaderFilenameOffset = 0,
+ kTarHeaderFilenameSize = 100,
+ kTarHeaderSizeOffset = 124,
+ kTarHeaderSizeSize = 12,
+ kTarHeaderTypeOffset = 156,
+ kTarHeaderTypeSize = 1,
+ kTarHeaderSize = 512,
+ };
+
+ enum TarType {
+ kTarAregType = '\0',
+ kTarRegType = '0',
+ kTarLnkType = '1',
+ kTarSymType = '2',
+ kTarChrType = '3',
+ kTarBlkType = '4',
+ kTarDirType = '5',
+ kTarFifoType = '6',
+ kTarContType = '7',
+ kTarXhdType = 'x',
+ kTarXglType = 'g',
+ };
+
+ bool HasNext() const {
+ return !EndOfArchive();
+ }
+
+ bool Next(char** filename, uint8_t** data, intptr_t* data_length) {
+ intptr_t startOfBlock = rs_.Position();
+ *filename = ReadFilename();
+ rs_.SetPosition(startOfBlock + kTarHeaderSizeOffset);
+ intptr_t size = ReadSize();
+ rs_.SetPosition(startOfBlock + kTarHeaderTypeOffset);
+ TarType type = ReadType();
+ SeekToNextBlock(kTarHeaderSize);
+ if ((type != kTarRegType) && (type != kTarAregType)) {
+ SkipContents(size);
+ return false;
+ }
+ ReadContents(data, size);
+ *data_length = size;
+ return true;
+ }
+
+ void SeekToNextBlock(intptr_t blockSize) {
+ intptr_t remainder = blockSize - (rs_.Position() % blockSize);
+ rs_.Advance(remainder);
+ }
+
+ uint8_t PeekByte(intptr_t i) const {
+ return *(rs_.AddressOfCurrentPosition() + i);
+ }
+
+ bool EndOfArchive() const {
+ if (rs_.PendingBytes() < (kTarHeaderSize * 2)) {
+ return true;
+ }
+ for (intptr_t i = 0; i < (kTarHeaderSize * 2); i++) {
+ if (PeekByte(i) != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ TarType ReadType() {
+ return static_cast<TarType>(ReadStream::Raw<1, uint8_t>::Read(&rs_));
+ }
+
+ void SkipContents(intptr_t size) {
+ rs_.Advance(size);
+ SeekToNextBlock(kTarHeaderSize);
+ }
+
+ intptr_t ReadCString(char** s, intptr_t length) {
+ intptr_t to_read = Utils::Minimum(length, rs_.PendingBytes());
+ char* result = new char[to_read + 1];
+ strncpy(result,
+ reinterpret_cast<const char*>(rs_.AddressOfCurrentPosition()),
+ to_read);
+ result[to_read] = '\0';
+ rs_.SetPosition(rs_.Position() + to_read);
+ *s = result;
+ return to_read;
+ }
+
+ intptr_t ReadSize() {
+ char* octalSize;
+ unsigned int size;
+
+ ReadCString(&octalSize, kTarHeaderSizeSize);
+ int result = sscanf(octalSize, "%o", &size);
+ delete[] octalSize;
+
+ if (result != 1) {
+ return 0;
+ }
+ return size;
+ }
+
+ char* ReadFilename() {
+ char* result;
+ intptr_t result_length = ReadCString(&result, kTarHeaderFilenameSize);
+ if (result[0] == '/') {
+ return result;
+ }
+ char* fixed_result = new char[result_length + 2]; // '/' + '\0'.
+ fixed_result[0] = '/';
+ strncpy(&fixed_result[1], result, result_length);
+ fixed_result[result_length + 1] = '\0';
+ delete[] result;
+ return fixed_result;
+ }
+
+ void ReadContents(uint8_t** data, intptr_t size) {
+ uint8_t* result = new uint8_t[size];
+ rs_.ReadBytes(result, size);
+ SeekToNextBlock(kTarHeaderSize);
+ *data = result;
+ }
+
+ ReadStream rs_;
+ GrowableArray<char*> filenames_;
+ GrowableArray<uint8_t*> contents_;
+ GrowableArray<intptr_t> content_lengths_;
+
+ DISALLOW_COPY_AND_ASSIGN(TarArchive);
+};
+
+
+static void ContentsFinalizer(void* isolate_callback_data,
+ Dart_WeakPersistentHandle handle,
+ void* peer) {
+ uint8_t* data = reinterpret_cast<uint8_t*>(peer);
+ delete[] data;
+}
+
+
+static void FilenameFinalizer(void* peer) {
+ char* filename = reinterpret_cast<char*>(peer);
+ delete[] filename;
+}
+
+
+DEFINE_NATIVE_ENTRY(VMService_DecodeAssets, 1) {
+ GET_NON_NULL_NATIVE_ARGUMENT(TypedData, data, arguments->NativeArgAt(0));
+ Api::Scope scope(thread);
+
+ Dart_Handle data_handle = Api::NewHandle(thread, data.raw());
+
+ Dart_TypedData_Type typ;
+ void* bytes;
+ intptr_t length;
+ Dart_Handle err = Dart_TypedDataAcquireData(
+ data_handle, &typ, &bytes, &length);
+ ASSERT(!Dart_IsError(err));
+
+ TarArchive archive(reinterpret_cast<uint8_t*>(bytes), length);
+ archive.Read();
+
+ err = Dart_TypedDataReleaseData(data_handle);
+ ASSERT(!Dart_IsError(err));
+
+ intptr_t archive_size = archive.Length();
+
+ const Array& result_list = Array::Handle(thread->zone(),
+ Array::New(2 * archive_size));
+
+ intptr_t idx = 0;
+ while (archive.HasMore()) {
+ char* filename = archive.NextFilename();
+ uint8_t* contents = archive.NextContent();
+ intptr_t contents_length = archive.NextContentLength();
+
+ Dart_Handle dart_filename = Dart_NewExternalLatin1String(
+ reinterpret_cast<uint8_t*>(filename),
+ strlen(filename),
+ filename,
+ FilenameFinalizer);
+ ASSERT(!Dart_IsError(dart_filename));
+
+ Dart_Handle dart_contents = Dart_NewExternalTypedData(
+ Dart_TypedData_kUint8, contents, contents_length);
+ ASSERT(!Dart_IsError(dart_contents));
+ Dart_NewWeakPersistentHandle(
+ dart_contents, contents, contents_length, ContentsFinalizer);
+
+ result_list.SetAt(idx, Api::UnwrapStringHandle(
+ thread->zone(), dart_filename));
+ result_list.SetAt(idx + 1, Api::UnwrapExternalTypedDataHandle(
+ thread->zone(), dart_contents));
+ idx += 2;
+ }
+
+ return result_list.raw();
+}
+
} // namespace dart
diff --git a/runtime/lib/vmservice_patch.dart b/runtime/lib/vmservice_patch.dart
index a885004..3db7bca 100644
--- a/runtime/lib/vmservice_patch.dart
+++ b/runtime/lib/vmservice_patch.dart
@@ -2,6 +2,25 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+patch class Asset {
+ /// Call to request assets from the embedder.
+ /* patch */ static HashMap<String, Asset> request() {
+ HashMap<String, Asset> assets = new HashMap<String, Asset>();
+ Uint8List tarBytes = _requestAssets();
+ if (tarBytes == null) {
+ return assets;
+ }
+ List assetList = _decodeAssets(tarBytes);
+ for (int i = 0; i < assetList.length; i += 2) {
+ var a = new Asset(assetList[i], assetList[i + 1]);
+ assets[a.name] = a;
+ }
+ return assets;
+ }
+}
+
+List _decodeAssets(Uint8List data) native "VMService_DecodeAssets";
+
patch bool sendIsolateServiceMessage(SendPort sp, List m)
native "VMService_SendIsolateServiceMessage";
patch void sendRootServiceMessage(List m)
@@ -10,4 +29,4 @@
patch void _onExit() native "VMService_OnExit";
patch bool _vmListenStream(String streamId) native "VMService_ListenStream";
patch void _vmCancelStream(String streamId) native "VMService_CancelStream";
-patch Uint8List _requestAssets() native "VMService_RequestAssets";
\ No newline at end of file
+patch Uint8List _requestAssets() native "VMService_RequestAssets";
diff --git a/runtime/observatory/lib/src/elements/class_ref.dart b/runtime/observatory/lib/src/elements/class_ref.dart
index 5eebe73..b8895c6 100644
--- a/runtime/observatory/lib/src/elements/class_ref.dart
+++ b/runtime/observatory/lib/src/elements/class_ref.dart
@@ -4,23 +4,33 @@
library class_ref_element;
+import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
import 'service_ref.dart';
+import 'dart:async';
@CustomTag('class-ref')
class ClassRefElement extends ServiceRefElement {
+ @observable bool asValue = false;
+
ClassRefElement.created() : super.created();
- refChanged(oldValue) {
- super.refChanged(oldValue);
- _updateShadowDom();
+ String makeExpandKey(String key) {
+ return '${expandKey}/${key}';
}
- void _updateShadowDom() {
- clearShadowRoot();
- if (ref == null) {
- return;
+ dynamic expander() {
+ return expandEvent;
+ }
+
+ void expandEvent(bool expand, Function onDone) {
+ if (expand) {
+ Class cls = ref;
+ cls.reload().then((result) {
+ return Future.wait(cls.fields.map((field) => field.reload()));
+ }).whenComplete(onDone);
+ } else {
+ onDone();
}
- insertLinkIntoShadowRoot(name, url, hoverText);
}
}
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/class_ref.html b/runtime/observatory/lib/src/elements/class_ref.html
index e3f908a..c3ddec7 100644
--- a/runtime/observatory/lib/src/elements/class_ref.html
+++ b/runtime/observatory/lib/src/elements/class_ref.html
@@ -1,8 +1,34 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="curly_block.html">
+<link rel="import" href="observatory_element.html">
<link rel="import" href="service_ref.html">
<polymer-element name="class-ref" extends="service-ref">
- <template><link rel="stylesheet" href="css/shared.css"></template>
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .indented {
+ margin-left: 1.5em;
+ font: 400 14px 'Montserrat', sans-serif;
+ line-height: 150%;
+ }
+ </style><!--
+ --><a on-click="{{ goto }}" _href="{{ url }}">{{ ref.name }}</a><!--
+ --><template if="{{ asValue }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+ <div class="indented">
+ <template repeat="{{ field in ref.fields }}">
+ <template if="{{ field.isStatic }}">
+ {{ field.name }} :
+ <any-service-ref ref="{{ field.staticValue }}"
+ expandKey="{{ makeExpandKey(field.name) }}">
+ </any-service-ref><br>
+ </template>
+ </template>
+ </div>
+ </curly-block>
+ </template><!--
+ --></template>
</polymer-element>
<script type="application/dart" src="class_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/class_tree.html b/runtime/observatory/lib/src/elements/class_tree.html
index 7f40600..c1e9635 100644
--- a/runtime/observatory/lib/src/elements/class_tree.html
+++ b/runtime/observatory/lib/src/elements/class_tree.html
@@ -27,16 +27,14 @@
}
</style>
<nav-bar>
- <top-nav-menu last="{{ true }}"></top-nav-menu>
+ <top-nav-menu></top-nav-menu>
+ <vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
+ <isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
+ <nav-menu link="{{ makeLink('/class-tree', isolate) }}" anchor="class hierarchy" last="{{ true }}"></nav-menu>
</nav-bar>
<div class="content-centered">
<h1>Class Hierarchy</h1>
<table id="tableTree" class="table">
- <thead id="tableTreeHeader">
- <tr>
- <th>Class</th>
- </tr>
- </thead>
<tbody id="tableTreeBody"></tbody>
</table>
</div>
diff --git a/runtime/observatory/lib/src/elements/class_view.dart b/runtime/observatory/lib/src/elements/class_view.dart
index 998f82d..8c67ebc 100644
--- a/runtime/observatory/lib/src/elements/class_view.dart
+++ b/runtime/observatory/lib/src/elements/class_view.dart
@@ -15,6 +15,7 @@
class ClassViewElement extends ObservatoryElement {
@published Class cls;
@observable ServiceMap instances;
+ @observable int reachableBytes;
@observable int retainedBytes;
@observable ObservableList mostRetained;
SampleBufferControlElement sampleBufferControlElement;
@@ -44,6 +45,12 @@
}
// TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
+ Future<ServiceObject> reachableSize(var dummy) {
+ return cls.isolate.getReachableSize(cls).then((Instance obj) {
+ reachableBytes = int.parse(obj.valueAsString);
+ });
+ }
+
Future<ServiceObject> retainedSize(var dummy) {
return cls.isolate.getRetainedSize(cls).then((Instance obj) {
retainedBytes = int.parse(obj.valueAsString);
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 5dadba6..6e59887 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -181,6 +181,19 @@
</div>
</div>
<div class="memberItem">
+ <div class="memberName">total reachable memory size</div>
+ <div class="memberValue">
+ <template if="{{ reachableBytes == null }}">
+ <eval-link callback="{{ reachableSize }}"
+ label="[calculate]">
+ </eval-link>
+ </template>
+ <template if="{{ reachableBytes != null }}">
+ {{ reachableBytes | formatSize }}
+ </template>
+ </div>
+ </div>
+ <div class="memberItem">
<div class="memberName">total retained memory size</div>
<div class="memberValue">
<template if="{{ retainedBytes == null }}">
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index f464581..cf78a26 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -2231,6 +2231,23 @@
busy = false;
});
}
+
+ @observable
+ get properLocals {
+ var locals = new List();
+ var homeMethod = frame.function.homeMethod;
+ if (homeMethod.dartOwner is Class && homeMethod.isStatic) {
+ locals.add(
+ {'name' : '<class>',
+ 'value' : homeMethod.dartOwner});
+ } else if (homeMethod.dartOwner is Library) {
+ locals.add(
+ {'name' : '<library>',
+ 'value' : homeMethod.dartOwner});
+ }
+ locals.addAll(frame.variables);
+ return locals;
+ }
}
@CustomTag('debugger-message')
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 5b74667..981f260 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -267,16 +267,13 @@
</source-inset>
</div>
<div class="flex-item-vars">
- <div style="padding:10px;" class="memberList">
- <template repeat="{{ v in frame.variables }}">
- <div class="memberItem">
- <div class="memberName">{{ v['name']}}</div>
- <div class="memberValue">
- <any-service-ref ref="{{ v['value'] }}"
- expandKey="{{ makeExpandKey(v['name']) }}">
- </any-service-ref>
- </div>
- </div>
+ <div style="padding-left:2em;" class="memberList">
+ <template repeat="{{ v in properLocals }}">
+ {{ v['name']}} :
+ <any-service-ref ref="{{ v['value'] }}"
+ expandKey="{{ makeExpandKey(v['name']) }}"
+ asValue="{{ true }}">
+ </any-service-ref><br>
</template>
</div>
</div>
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
index 017e28d..9a39cbb 100644
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ b/runtime/observatory/lib/src/elements/flag_list.html
@@ -8,6 +8,7 @@
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu></top-nav-menu>
+ <vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
<nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
</nav-bar>
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index 57dcec9..7125f16 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -87,6 +87,9 @@
expandKey="{{ makeExpandKey(index.toString()) }}">
</any-service-ref><br>
</template>
+ <template if="{{ ref.length != ref.elements.length }}">
+ <div><em>{{ ref.length - ref.elements.length }} omitted elements</em></div>
+ </template>
</div>
</curly-block>
</template>
@@ -103,6 +106,9 @@
expandKey="{{ makeExpandKey('value') }}">
</any-service-ref><br>
</template>
+ <template if="{{ ref.length != ref.association.length }}">
+ <div><em>{{ ref.length - ref.association.length }} omitted association</em></div>
+ </template>
</div>
</curly-block>
</template>
@@ -115,6 +121,9 @@
[ {{ index }} ]
{{ ref.typedElements[index].toString() }}<br>
</template>
+ <template if="{{ ref.length != ref.typedElements.length }}">
+ <div><em>{{ ref.length - ref.typedElements.length }} omitted elements</em></div>
+ </template>
</div>
</curly-block>
</template>
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index 28f093f..f54059f 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -154,7 +154,7 @@
</template>
<template if="{{ instance.elements.isNotEmpty }}">
- elements ({{ instance.elements.length }})
+ elements ({{ instance.length }})
<curly-block expand="{{ instance.elements.length <= 100 }}">
<div class="memberList">
<template repeat="{{ index in instance.elements.asMap().keys }}">
@@ -166,12 +166,20 @@
</div>
</div>
</template>
+ <template if="{{ instance.length != instance.elements.length }}">
+ <div class="memberItem">
+ <div class="memberName">...</div>
+ <div class="memberValue">
+ <em>{{ instance.length - instance.elements.length }} omitted elements</em>
+ </div>
+ </div>
+ </template>
</div>
</curly-block><br><br>
</template>
<template if="{{ instance.associations.isNotEmpty }}">
- associations ({{ instance.elements.length }})
+ associations ({{ instance.length }})
<curly-block expand="{{ instance.associations.length <= 100 }}">
<div class="memberList">
<template repeat="{{ association in instance.associations }}">
@@ -184,12 +192,20 @@
</div>
</div>
</template>
+ <template if="{{ instance.length != instance.associations.length }}">
+ <div class="memberItem">
+ <div class="memberName">...</div>
+ <div class="memberValue">
+ <em>{{ instance.length - instance.associations.length }} omitted associations</em>
+ </div>
+ </div>
+ </template>
</div>
</curly-block><br><br>
</template>
<template if="{{ instance.typedElements.isNotEmpty }}">
- elements ({{ instance.typedElements.length }})
+ elements ({{ instance.length }})
<curly-block expand="{{ instance.typedElements.length <= 100 }}">
<div class="memberList">
<template repeat="{{ index in instance.typedElements.asMap().keys }}">
@@ -198,6 +214,14 @@
<div class="memberValue">{{ instance.typedElements[index].toString() }}</div>
</div>
</template>
+ <template if="{{ instance.length != instance.typedElements.length }}">
+ <div class="memberItem">
+ <div class="memberName">...</div>
+ <div class="memberValue">
+ <em>{{ instance.length - instance.elements.length }} omitted elements</em>
+ </div>
+ </div>
+ </template>
</div>
</curly-block><br><br>
</template>
diff --git a/runtime/observatory/lib/src/elements/library_ref.dart b/runtime/observatory/lib/src/elements/library_ref.dart
index cbe7d4b..4f65a39 100644
--- a/runtime/observatory/lib/src/elements/library_ref.dart
+++ b/runtime/observatory/lib/src/elements/library_ref.dart
@@ -4,10 +4,33 @@
library library_ref_element;
+import 'package:observatory/service.dart';
import 'package:polymer/polymer.dart';
import 'service_ref.dart';
+import 'dart:async';
@CustomTag('library-ref')
class LibraryRefElement extends ServiceRefElement {
+ @observable bool asValue = false;
+
LibraryRefElement.created() : super.created();
+
+ String makeExpandKey(String key) {
+ return '${expandKey}/${key}';
+ }
+
+ dynamic expander() {
+ return expandEvent;
+ }
+
+ void expandEvent(bool expand, Function onDone) {
+ if (expand) {
+ Library lib = ref;
+ lib.reload().then((result) {
+ return Future.wait(lib.variables.map((field) => field.reload()));
+ }).whenComplete(onDone);
+ } else {
+ onDone();
+ }
+ }
}
diff --git a/runtime/observatory/lib/src/elements/library_ref.html b/runtime/observatory/lib/src/elements/library_ref.html
index 30272a4..a4313c1 100644
--- a/runtime/observatory/lib/src/elements/library_ref.html
+++ b/runtime/observatory/lib/src/elements/library_ref.html
@@ -1,15 +1,39 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
+<link rel="import" href="curly_block.html">
+<link rel="import" href="observatory_element.html">
<link rel="import" href="service_ref.html">
<polymer-element name="library-ref" extends="service-ref">
- <template><link rel="stylesheet" href="css/shared.css"><!--
- --><template if="{{ nameIsEmpty }}"><!--
- --><a on-click="{{ goto }}" _href="{{ url }}">unnamed</a><!--
- --></template><!--
- --><template if="{{ !nameIsEmpty }}"><!--
- --><a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a><!--
- --></template><!--
- --></template>
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ .indented {
+ margin-left: 1.5em;
+ font: 400 14px 'Montserrat', sans-serif;
+ line-height: 150%;
+ }
+ </style>
+ <template if="{{ nameIsEmpty }}">
+ <a on-click="{{ goto }}" _href="{{ url }}">unnamed</a>
+ </template>
+ <template if="{{ !nameIsEmpty }}">
+ <a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
+ </template>
+ <template if="{{ asValue }}">
+ <curly-block callback="{{ expander() }}" expandKey="{{ expandKey }}">
+ <div class="indented">
+ <template repeat="{{ field in ref.variables }}">
+ <template if="{{ field.isStatic }}">
+ {{ field.name }} :
+ <any-service-ref ref="{{ field.staticValue }}"
+ expandKey="{{ makeExpandKey(field.name) }}">
+ </any-service-ref><br>
+ </template>
+ </template>
+ </div>
+ </curly-block>
+ </template>
+ </template>
</polymer-element>
<script type="application/dart" src="library_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/object_common.dart b/runtime/observatory/lib/src/elements/object_common.dart
index eea85ff..1deb5d6 100644
--- a/runtime/observatory/lib/src/elements/object_common.dart
+++ b/runtime/observatory/lib/src/elements/object_common.dart
@@ -15,10 +15,18 @@
@published ServiceMap path;
@published ServiceMap inboundReferences;
@observable int retainedBytes = null;
+ @observable int reachableBytes = null;
ObjectCommonElement.created() : super.created();
// TODO(koda): Add no-arg "calculate-link" instead of reusing "eval-link".
+ Future<ServiceObject> reachableSize(var dummy) {
+ return object.isolate.getReachableSize(object).then((Instance obj) {
+ // TODO(turnidge): Handle collected/expired objects gracefully.
+ reachableBytes = int.parse(obj.valueAsString);
+ });
+ }
+
Future<ServiceObject> retainedSize(var dummy) {
return object.isolate.getRetainedSize(object).then((Instance obj) {
// TODO(turnidge): Handle collected/expired objects gracefully.
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index 7cad87a..14311e0 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -26,6 +26,20 @@
<div class="memberValue">{{ object.size | formatSize }}</div>
</div>
+ <div class="memberItem" title="Space reachable from this object, excluding class references">
+ <div class="memberName">reachable size</div>
+ <div class="memberValue">
+ <template if="{{ reachableBytes == null }}">
+ <eval-link callback="{{ reachableSize }}"
+ label="[calculate]">
+ </eval-link>
+ </template>
+ <template if="{{ reachableBytes != null }}">
+ {{ reachableBytes | formatSize }}
+ </template>
+ </div>
+ </div>
+
<div class="memberItem" title="Space that would be reclaimed if references to this object were replaced with null">
<div class="memberName">retained size</div>
<div class="memberValue">
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index 9798795..e9aad6d 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -5,10 +5,14 @@
library service_ref_element;
import 'dart:html';
+
import 'package:logging/logging.dart';
-import 'package:polymer/polymer.dart';
-import 'observatory_element.dart';
import 'package:observatory/service.dart';
+import 'package:polymer/polymer.dart';
+
+import 'class_ref.dart';
+import 'library_ref.dart';
+import 'observatory_element.dart';
@CustomTag('service-ref')
class ServiceRefElement extends ObservatoryElement {
@@ -81,14 +85,16 @@
class AnyServiceRefElement extends ObservatoryElement {
@published ServiceObject ref;
@published String expandKey;
+ @published bool asValue = false;
AnyServiceRefElement.created() : super.created();
Element _constructElementForRef() {
var type = ref.type;
switch (type) {
case 'Class':
- ServiceRefElement element = new Element.tag('class-ref');
+ ClassRefElement element = new Element.tag('class-ref');
element.ref = ref;
+ element.asValue = asValue;
return element;
case 'Code':
ServiceRefElement element = new Element.tag('code-ref');
@@ -111,8 +117,9 @@
element.ref = ref;
return element;
case 'Library':
- ServiceRefElement element = new Element.tag('library-ref');
+ LibraryRefElement element = new Element.tag('library-ref');
element.ref = ref;
+ element.asValue = asValue;
return element;
case 'Object':
ServiceRefElement element = new Element.tag('object-ref');
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index 95764ea..50b063d 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -3,19 +3,21 @@
<link rel="import" href="observatory_element.html">
<polymer-element name="timeline-page" extends="observatory-element">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <style>
- </style>
- <nav-bar>
- <top-nav-menu></top-nav-menu>
- <nav-menu link="{{ makeLink('/timeline') }}" anchor="timeline" last="{{ true }}"></nav-menu>
- <nav-refresh callback="{{ refresh }}"></nav-refresh>
- <nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
- <nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
- <nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
- </nav-bar>
- <iframe id="root" frameborder="0" src="../../../../timeline.html"></iframe>
- </template>
+ <template>
+ <link rel="stylesheet" href="css/shared.css">
+ <style>
+ </style>
+ <nav-bar>
+ <top-nav-menu></top-nav-menu>
+ <vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
+ <nav-menu link="{{ makeLink('/timeline') }}" anchor="timeline" last="{{ true }}"></nav-menu>
+ <nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
+ <nav-refresh callback="{{ recordOn }}" label="Start recording"></nav-refresh>
+ <nav-refresh callback="{{ recordOff }}" label="Stop recording"></nav-refresh>
+ </nav-bar>
+ <iframe id="root" frameborder="0" src="../../../../timeline.html">
+ </iframe>
+ </template>
</polymer-element>
<script type="application/dart" src="timeline_page.dart"></script>
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index f7775c1..8c9717f 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -4,6 +4,11 @@
part of service;
+// Some value smaller than the object ring, so requesting a large array
+// doesn't result in an expired ref because the elements lapped it in the
+// object ring.
+const int kDefaultFieldLimit = 100;
+
/// Helper function for canceling a Future<StreamSubscription>.
Future cancelFutureSubscription(
Future<StreamSubscription> subscriptionFuture) async {
@@ -284,6 +289,7 @@
Future<ObservableMap> _fetchDirect() {
Map params = {
'objectId': id,
+ 'count': kDefaultFieldLimit,
};
return isolate.invokeRpcNoUpgrade('getObject', params);
}
@@ -1288,6 +1294,7 @@
}
Map params = {
'objectId': objectId,
+ 'count': kDefaultFieldLimit,
};
return isolate.invokeRpc('getObject', params);
}
@@ -1688,6 +1695,13 @@
return invokeRpc('evaluateInFrame', params);
}
+ Future<ServiceObject> getReachableSize(ServiceObject target) {
+ Map params = {
+ 'targetId': target.id,
+ };
+ return invokeRpc('_getReachableSize', params);
+ }
+
Future<ServiceObject> getRetainedSize(ServiceObject target) {
Map params = {
'targetId': target.id,
@@ -2632,6 +2646,14 @@
icDataArray = map['_icDataArray'];
field = map['_field'];
}
+
+ ServiceFunction get homeMethod {
+ var m = this;
+ while (m.dartOwner is ServiceFunction) {
+ m = m.dartOwner;
+ }
+ return m;
+ }
}
diff --git a/runtime/observatory/tests/service/get_object_rpc_test.dart b/runtime/observatory/tests/service/get_object_rpc_test.dart
index 882b016..6bfa71f 100644
--- a/runtime/observatory/tests/service/get_object_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_object_rpc_test.dart
@@ -774,7 +774,7 @@
(Isolate isolate) async {
// Call eval to get a class id.
var evalResult = await eval(isolate, 'new _DummyClass()');
- var id = "${evalResult['class']['id']}/fields/0";
+ var id = "${evalResult['class']['id']}/fields/dummyVar";
var params = {
'objectId': id,
};
@@ -796,7 +796,7 @@
(Isolate isolate) async {
// Call eval to get a class id.
var evalResult = await eval(isolate, 'new _DummyClass()');
- var id = "${evalResult['class']['id']}/fields/9999";
+ var id = "${evalResult['class']['id']}/fields/mythicalField";
var params = {
'objectId': id,
};
diff --git a/runtime/observatory/tests/service/reachable_size_test.dart b/runtime/observatory/tests/service/reachable_size_test.dart
new file mode 100644
index 0000000..5c346e3
--- /dev/null
+++ b/runtime/observatory/tests/service/reachable_size_test.dart
@@ -0,0 +1,71 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'test_helper.dart';
+
+class Pair {
+ var x, y;
+}
+
+var p1;
+var p2;
+
+buildGraph() {
+ p1 = new Pair();
+ p2 = new Pair();
+
+ // Adds to both reachable and retained size.
+ p1.x = new List();
+ p2.x = new List();
+
+ // Adds to reachable size only.
+ p1.y = p2.y = new List();
+}
+
+getReachableSize(ServiceObject obj) {
+ return obj.isolate.getReachableSize(obj).then((Instance obj) {
+ return int.parse(obj.valueAsString);
+ });
+}
+
+getRetainedSize(ServiceObject obj) {
+ return obj.isolate.getRetainedSize(obj).then((Instance obj) {
+ return int.parse(obj.valueAsString);
+ });
+}
+
+var tests = [
+(Isolate isolate) async {
+ Instance p1 = await rootLibraryFieldValue(isolate, "p1");
+ Instance p2 = await rootLibraryFieldValue(isolate, "p2");
+
+ // In general, shallow <= retained <= reachable. In this program,
+ // 0 < shallow < retained < reachable.
+
+ int p1_shallow = p1.size;
+ int p1_retained = await getRetainedSize(p1);
+ int p1_reachable = await getReachableSize(p1);
+
+ expect(0, lessThan(p1_shallow));
+ expect(p1_shallow, lessThan(p1_retained));
+ expect(p1_retained, lessThan(p1_reachable));
+
+ int p2_shallow = p2.size;
+ int p2_retained = await getRetainedSize(p2);
+ int p2_reachable = await getReachableSize(p2);
+
+ expect(0, lessThan(p2_shallow));
+ expect(p2_shallow, lessThan(p2_retained));
+ expect(p2_retained, lessThan(p2_reachable));
+
+ expect(p1_shallow, equals(p2_shallow));
+ expect(p1_retained, equals(p2_retained));
+ expect(p1_reachable, equals(p2_reachable));
+},
+];
+
+main(args) => runIsolateTests(args, tests, testeeBefore: buildGraph);
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 6248b43..58de4e6 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -319,6 +319,17 @@
}
+Future<Instance> rootLibraryFieldValue(Isolate isolate,
+ String fieldName) async {
+ Library rootLib = await isolate.rootLibrary.load();
+ Field field = rootLib.variables.singleWhere((v) => v.name == fieldName);
+ await field.load();
+ Instance value = field.staticValue;
+ await value.load();
+ return value;
+}
+
+
/// Runs [tests] in sequence, each of which should take an [Isolate] and
/// return a [Future]. Code for setting up state can run before and/or
/// concurrently with the tests. Uses [mainArgs] to determine whether
diff --git a/runtime/observatory/tests/ui/inspector.dart b/runtime/observatory/tests/ui/inspector.dart
index fd6d0c3..c34f2d9 100644
--- a/runtime/observatory/tests/ui/inspector.dart
+++ b/runtime/observatory/tests/ui/inspector.dart
@@ -24,6 +24,10 @@
class A <T> {}
class B <S extends num> {}
+class S {}
+class M {}
+class MA extends S with M {}
+
class Node {
static var classField;
@@ -112,6 +116,10 @@
return x;
}
+ static staticMain() {
+ node.main();
+ }
+
main() {
print("Started main");
@@ -240,7 +248,7 @@
Node.classField = 'Class field value';
typed = new Typed();
node = new Node();
- node.main();
+ Node.staticMain();
}
class C {
diff --git a/runtime/platform/json.cc b/runtime/platform/json.cc
deleted file mode 100644
index 6457a87..0000000
--- a/runtime/platform/json.cc
+++ /dev/null
@@ -1,636 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "platform/json.h"
-
-#include "platform/assert.h"
-#include "platform/globals.h"
-#include "platform/utils.h"
-#include "vm/os.h"
-
-namespace dart {
-
-JSONScanner::JSONScanner(const char* json_text) {
- SetText(json_text);
-}
-
-
-void JSONScanner::SetText(const char* json_text) {
- current_pos_ = json_text;
- token_start_ = json_text;
- token_length_ = 0;
- token_ = TokenIllegal;
-}
-
-
-void JSONScanner::Recognize(Token t) {
- ++current_pos_;
- token_ = t;
-}
-
-
-bool JSONScanner::IsLetter(char ch) const {
- return (('A' <= ch) && (ch <= 'Z')) || (('a' <= ch) && (ch <= 'z'));
-}
-
-
-bool JSONScanner::IsDigit(char ch) const {
- return ('0' <= ch) && (ch <= '9');
-}
-
-
-bool JSONScanner::IsLiteral(const char* literal) {
- int i = 0;
- while ((literal[i] != '\0') && (current_pos_[i] == literal[i])) {
- i++;
- }
- if ((literal[i] == '\0') && !IsLetter(current_pos_[i])) {
- current_pos_ += i;
- return true;
- }
- return false;
-}
-
-
-bool JSONScanner::IsStringLiteral(const char* literal) const {
- if (token_ != TokenString) {
- return false;
- }
- int i = 0;
- while ((i < token_length_) && (token_start_[i] == literal[i])) {
- i++;
- }
- return (i == token_length_) && (literal[i] == '\0');
-}
-
-
-void JSONScanner::Skip(Token matching_token) {
- while (!EOM() && (token_ != TokenIllegal)) {
- Scan();
- if (token_ == TokenLBrace) {
- Skip(TokenRBrace);
- } else if (token_ == TokenLBrack) {
- Skip(TokenRBrack);
- } else if (token_ == matching_token) {
- return;
- } else if ((token_ == TokenRBrace) || (token_ == TokenRBrack)) {
- // Mismatched brace or bracket.
- token_ = TokenIllegal;
- }
- }
-}
-
-
-void JSONScanner::ScanString() {
- ASSERT(*current_pos_ == '"');
- ++current_pos_;
- token_start_ = current_pos_;
- while (*current_pos_ != '"') {
- if (*current_pos_ == '\0') {
- token_length_ = 0;
- token_ = TokenIllegal;
- return;
- } else if (*current_pos_ == '\\') {
- ++current_pos_;
- if (*current_pos_ == '"') {
- // Consume escaped double quote.
- ++current_pos_;
- }
- } else {
- ++current_pos_;
- }
- }
- token_ = TokenString;
- token_length_ = current_pos_ - token_start_;
- ++current_pos_;
-}
-
-
-void JSONScanner::ScanNumber() {
- if (*current_pos_ == '-') {
- ++current_pos_;
- }
- if (!IsDigit(*current_pos_)) {
- token_ = TokenIllegal;
- token_length_ = 0;
- return;
- }
- while (IsDigit(*current_pos_)) {
- ++current_pos_;
- }
- if ((*current_pos_ == '.') ||
- (*current_pos_ == 'e') ||
- (*current_pos_ == 'E')) {
- // Floating point numbers not supported.
- token_ = TokenIllegal;
- token_length_ = 0;
- return;
- }
- token_ = TokenInteger;
- token_length_ = current_pos_ - token_start_;
-}
-
-
-void JSONScanner::Scan() {
- while ((*current_pos_ == ' ') ||
- (*current_pos_ == '\t') ||
- (*current_pos_ == '\n')) {
- ++current_pos_;
- }
- token_start_ = current_pos_;
- if (*current_pos_ == '\0') {
- token_length_ = 0;
- token_ = TokenEOM;
- return;
- }
- switch (*current_pos_) {
- case '{':
- Recognize(TokenLBrace);
- break;
- case '}':
- Recognize(TokenRBrace);
- break;
- case '[':
- Recognize(TokenLBrack);
- break;
- case ']':
- Recognize(TokenRBrack);
- break;
- case ':':
- Recognize(TokenColon);
- break;
- case ',':
- Recognize(TokenComma);
- break;
- case '"':
- ScanString();
- break;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- case '-':
- ScanNumber();
- break;
- default:
- if (IsLiteral("true")) {
- token_ = TokenTrue;
- token_length_ = 4;
- } else if (IsLiteral("false")) {
- token_ = TokenFalse;
- token_length_ = 5;
- } else if (IsLiteral("null")) {
- token_ = TokenNull;
- token_length_ = 4;
- } else {
- token_length_ = 0;
- token_ = TokenIllegal;
- }
- }
-}
-
-
-JSONReader::JSONReader(const char* json_object)
-: scanner_(json_object) {
- Set(json_object);
-}
-
-
-void JSONReader::Set(const char* json_object) {
- scanner_.SetText(json_object);
- json_object_ = json_object;
- error_ = false;
-}
-
-
-bool JSONReader::CheckMessage() {
- scanner_.SetText(json_object_);
- scanner_.Scan();
- CheckObject();
- return true;
-}
-
-
-void JSONReader::CheckValue() {
- switch (scanner_.CurrentToken()) {
- case JSONScanner::TokenLBrace:
- CheckObject();
- break;
- case JSONScanner::TokenLBrack:
- CheckArray();
- break;
- case JSONScanner::TokenString: {
- // Check the encoding.
- const char* s = ValueChars();
- int remaining = ValueLen();
- while (remaining > 0) {
- if ((*s == '\n') || (*s == '\t')) {
- OS::Print("Un-escaped character in JSON string: '%s'\n",
- ValueChars());
- FATAL("illegal character in JSON string value");
- }
- s++;
- remaining--;
- }
- scanner_.Scan();
- break;
- }
- case JSONScanner::TokenInteger:
- case JSONScanner::TokenTrue:
- case JSONScanner::TokenFalse:
- case JSONScanner::TokenNull:
- scanner_.Scan();
- break;
- default:
- OS::Print("Malformed JSON: expected a value but got '%s'\n",
- scanner_.TokenChars());
- FATAL("illegal JSON value found");
- }
-}
-
-
-#if defined (DEBUG)
-#define CHECK_TOKEN(token) \
- if (scanner_.CurrentToken() != token) { \
- OS::Print("Malformed JSON: expected %s but got '%s'\n", \
- #token, scanner_.TokenChars()); \
- intptr_t offset = scanner_.TokenChars() - this->json_object_; \
- OS::Print("Malformed JSON: expected %s at offset %" Pd "of buffer:\n%s\n", \
- #token, offset, this->json_object_); \
- ASSERT(scanner_.CurrentToken() == token); \
- }
-#else
-#define CHECK_TOKEN(token)
-#endif
-
-
-void JSONReader::CheckArray() {
- CHECK_TOKEN(JSONScanner::TokenLBrack);
- scanner_.Scan();
- while (scanner_.CurrentToken() != JSONScanner::TokenRBrack) {
- CheckValue();
- if (scanner_.CurrentToken() != JSONScanner::TokenComma) {
- break;
- }
- scanner_.Scan();
- }
- CHECK_TOKEN(JSONScanner::TokenRBrack);
- scanner_.Scan();
-}
-
-
-void JSONReader::CheckObject() {
- CHECK_TOKEN(JSONScanner::TokenLBrace);
- scanner_.Scan();
- while (scanner_.CurrentToken() == JSONScanner::TokenString) {
- scanner_.Scan();
- CHECK_TOKEN(JSONScanner::TokenColon);
- scanner_.Scan();
- CheckValue();
- if (scanner_.CurrentToken() != JSONScanner::TokenComma) {
- break;
- }
- scanner_.Scan();
- }
- CHECK_TOKEN(JSONScanner::TokenRBrace);
- scanner_.Scan();
-}
-
-#undef CHECK_TOKEN
-
-
-bool JSONReader::Seek(const char* name) {
- error_ = false;
- scanner_.SetText(json_object_);
- scanner_.Scan();
- if (scanner_.CurrentToken() != JSONScanner::TokenLBrace) {
- error_ = true;
- return false;
- }
- scanner_.Scan();
- if (scanner_.CurrentToken() == JSONScanner::TokenRBrace) {
- return false;
- }
- while (scanner_.CurrentToken() == JSONScanner::TokenString) {
- bool found = scanner_.IsStringLiteral(name);
- scanner_.Scan();
- if (scanner_.CurrentToken() != JSONScanner::TokenColon) {
- error_ = true;
- return false;
- }
- scanner_.Scan();
- switch (scanner_.CurrentToken()) {
- case JSONScanner::TokenString:
- case JSONScanner::TokenInteger:
- case JSONScanner::TokenLBrace:
- case JSONScanner::TokenLBrack:
- case JSONScanner::TokenTrue:
- case JSONScanner::TokenFalse:
- case JSONScanner::TokenNull:
- // Found a legal value.
- if (found) {
- return true;
- }
- break;
- default:
- error_ = true;
- return false;
- }
- // Skip the value.
- if (scanner_.CurrentToken() == JSONScanner::TokenLBrace) {
- scanner_.Skip(JSONScanner::TokenRBrace);
- if (scanner_.CurrentToken() != JSONScanner::TokenRBrace) {
- error_ = true;
- return false;
- }
- } else if (scanner_.CurrentToken() == JSONScanner::TokenLBrack) {
- scanner_.Skip(JSONScanner::TokenRBrack);
- if (scanner_.CurrentToken() != JSONScanner::TokenRBrack) {
- error_ = true;
- return false;
- }
- }
- scanner_.Scan(); // Value or closing brace or bracket.
- if (scanner_.CurrentToken() == JSONScanner::TokenComma) {
- scanner_.Scan();
- } else if (scanner_.CurrentToken() == JSONScanner::TokenRBrace) {
- return false;
- } else {
- error_ = true;
- return false;
- }
- }
- error_ = true;
- return false;
-}
-
-
-const char* JSONReader::EndOfObject() {
- bool found = Seek("***"); // Look for illegally named value.
- ASSERT(!found);
- if (!found && !error_) {
- const char* s = scanner_.TokenChars();
- ASSERT(*s == '}');
- return s;
- }
- return NULL;
-}
-
-
-JSONReader::JSONType JSONReader::Type() const {
- if (error_) {
- return kNone;
- }
- switch (scanner_.CurrentToken()) {
- case JSONScanner::TokenString:
- return kString;
- case JSONScanner::TokenInteger:
- return kInteger;
- case JSONScanner::TokenLBrace:
- return kObject;
- case JSONScanner::TokenLBrack:
- return kArray;
- case JSONScanner::TokenTrue:
- case JSONScanner::TokenFalse:
- case JSONScanner::TokenNull:
- return kLiteral;
- default:
- return kNone;
- }
-}
-
-
-void JSONReader::GetRawValueChars(char* buf, intptr_t buflen) const {
- if (Type() == kNone) {
- return;
- }
- intptr_t max = buflen - 1;
- if (ValueLen() < max) {
- max = ValueLen();
- }
- const char* val = ValueChars();
- intptr_t i = 0;
- for (; i < max; i++) {
- buf[i] = val[i];
- }
- buf[i] = '\0';
-}
-
-
-void JSONReader::GetDecodedValueChars(char* buf, intptr_t buflen) const {
- if (Type() == kNone) {
- return;
- }
- const intptr_t last_idx = buflen - 1;
- const intptr_t value_len = ValueLen();
- const char* val = ValueChars();
- intptr_t buf_idx = 0;
- intptr_t val_idx = 0;
- while ((buf_idx < last_idx) && (val_idx < value_len)) {
- char ch = val[val_idx];
- val_idx++;
- buf[buf_idx] = ch;
- if ((ch == '\\') && (val_idx < value_len)) {
- switch (val[val_idx]) {
- case '"':
- case '\\':
- case '/':
- buf[buf_idx] = val[val_idx];
- val_idx++;
- break;
- case 'b':
- buf[buf_idx] = '\b';
- val_idx++;
- break;
- case 'f':
- buf[buf_idx] = '\f';
- val_idx++;
- break;
- case 'n':
- buf[buf_idx] = '\n';
- val_idx++;
- break;
- case 'r':
- buf[buf_idx] = '\r';
- val_idx++;
- break;
- case 't':
- buf[buf_idx] = '\t';
- val_idx++;
- break;
- case 'u':
- // \u00XX
- // If the value is malformed or > 255, ignore and copy the
- // encoded characters.
- if ((val_idx < value_len - 4) &&
- (val[val_idx + 1] == '0') && (val[val_idx + 2] == '0') &&
- Utils::IsHexDigit(val[val_idx + 3]) &&
- Utils::IsHexDigit(val[val_idx + 4])) {
- buf[buf_idx] = 16 * Utils::HexDigitToInt(val[val_idx + 3]) +
- Utils::HexDigitToInt(val[val_idx + 4]);
- val_idx += 5;
- }
- break;
- default:
- // Nothing. Copy the character after the backslash
- // in the next loop iteration.
- break;
- }
- }
- buf_idx++;
- }
- buf[buf_idx] = '\0';
-}
-
-
-TextBuffer::TextBuffer(intptr_t buf_size) {
- ASSERT(buf_size > 0);
- buf_ = reinterpret_cast<char*>(malloc(buf_size));
- buf_size_ = buf_size;
- Clear();
-}
-
-
-TextBuffer::~TextBuffer() {
- free(buf_);
- buf_ = NULL;
-}
-
-
-void TextBuffer::Clear() {
- msg_len_ = 0;
- buf_[0] = '\0';
-}
-
-
-const char* TextBuffer::Steal() {
- const char* r = buf_;
- buf_ = NULL;
- buf_size_ = 0;
- msg_len_ = 0;
- return r;
-}
-
-
-void TextBuffer::AddChar(char ch) {
- EnsureCapacity(sizeof(ch));
- buf_[msg_len_] = ch;
- msg_len_++;
- buf_[msg_len_] = '\0';
-}
-
-
-intptr_t TextBuffer::Printf(const char* format, ...) {
- va_list args;
- va_start(args, format);
- intptr_t remaining = buf_size_ - msg_len_;
- ASSERT(remaining >= 0);
- intptr_t len = OS::VSNPrint(buf_ + msg_len_, remaining, format, args);
- va_end(args);
- if (len >= remaining) {
- EnsureCapacity(len);
- remaining = buf_size_ - msg_len_;
- ASSERT(remaining > len);
- va_list args2;
- va_start(args2, format);
- intptr_t len2 = OS::VSNPrint(buf_ + msg_len_, remaining, format, args2);
- va_end(args2);
- ASSERT(len == len2);
- }
- msg_len_ += len;
- buf_[msg_len_] = '\0';
- return len;
-}
-
-
-// Write a UTF-16 code unit so it can be read by a JSON parser in a string
-// literal. Use escape sequences for characters other than printable ASCII.
-void TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
- switch (codeunit) {
- case '"':
- Printf("%s", "\\\"");
- break;
- case '\\':
- Printf("%s", "\\\\");
- break;
- case '/':
- Printf("%s", "\\/");
- break;
- case '\b':
- Printf("%s", "\\b");
- break;
- case '\f':
- Printf("%s", "\\f");
- break;
- case '\n':
- Printf("%s", "\\n");
- break;
- case '\r':
- Printf("%s", "\\r");
- break;
- case '\t':
- Printf("%s", "\\t");
- break;
- default:
- if (codeunit < 0x20) {
- // Encode character as \u00HH.
- uint32_t digit2 = (codeunit >> 4) & 0xf;
- uint32_t digit3 = (codeunit & 0xf);
- Printf("\\u00%c%c",
- digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
- digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
- } else if (codeunit > 127) {
- // Encode character as \uHHHH.
- uint32_t digit0 = (codeunit >> 12) & 0xf;
- uint32_t digit1 = (codeunit >> 8) & 0xf;
- uint32_t digit2 = (codeunit >> 4) & 0xf;
- uint32_t digit3 = (codeunit & 0xf);
- Printf("\\u%c%c%c%c",
- digit0 > 9 ? 'A' + (digit0 - 10) : '0' + digit0,
- digit1 > 9 ? 'A' + (digit1 - 10) : '0' + digit1,
- digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
- digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
- } else {
- AddChar(codeunit);
- }
- }
-}
-
-
-void TextBuffer::AddString(const char* s) {
- Printf("%s", s);
-}
-
-
-void TextBuffer::AddEscapedString(const char* s) {
- intptr_t len = strlen(s);
- for (int i = 0; i < len; i++) {
- EscapeAndAddCodeUnit(s[i]);
- }
-}
-
-
-void TextBuffer::EnsureCapacity(intptr_t len) {
- intptr_t remaining = buf_size_ - msg_len_;
- if (remaining <= len) {
- const int kBufferSpareCapacity = 64; // Somewhat arbitrary.
- // TODO(turnidge): do we need to guard against overflow or other
- // security issues here? Text buffers are used by the debugger
- // to send user-controlled data (e.g. values of string variables) to
- // the debugger front-end.
- intptr_t new_size = buf_size_ + len + kBufferSpareCapacity;
- char* new_buf = reinterpret_cast<char*>(realloc(buf_, new_size));
- ASSERT(new_buf != NULL);
- buf_ = new_buf;
- buf_size_ = new_size;
- }
-}
-
-} // namespace dart
diff --git a/runtime/platform/json.h b/runtime/platform/json.h
deleted file mode 100644
index 35e975f0..0000000
--- a/runtime/platform/json.h
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef PLATFORM_JSON_H_
-#define PLATFORM_JSON_H_
-
-#include "vm/allocation.h"
-#include "vm/globals.h"
-
-namespace dart {
-
-
-// A low level interface to tokenize JSON strings.
-class JSONScanner : ValueObject {
- public:
- enum Token {
- TokenIllegal = 0,
- TokenLBrace,
- TokenRBrace,
- TokenLBrack,
- TokenRBrack,
- TokenColon,
- TokenComma,
- TokenString,
- TokenInteger,
- TokenTrue,
- TokenFalse,
- TokenNull,
- TokenEOM
- };
- explicit JSONScanner(const char* json_text);
-
- void SetText(const char* json_text);
- void Scan();
- Token CurrentToken() const { return token_; }
- bool EOM() const { return token_ == TokenEOM; }
- const char* TokenChars() const { return token_start_; }
- int TokenLen() const { return token_length_; }
- bool IsStringLiteral(const char* literal) const;
- void Skip(Token matching_token);
-
- private:
- bool IsLetter(char ch) const;
- bool IsDigit(char ch) const;
- bool IsLiteral(const char* literal);
- void ScanNumber();
- void ScanString();
- void Recognize(Token t);
-
- const char* current_pos_;
- const char* token_start_;
- int token_length_;
- Token token_;
-};
-
-
-// JSONReader is a higher level interface that allows for lookup of
-// name-value pairs in JSON objects.
-class JSONReader : ValueObject {
- public:
- enum JSONType {
- kString,
- kInteger,
- kObject,
- kArray,
- kLiteral,
- kNone
- };
-
- explicit JSONReader(const char* json_object);
- void Set(const char* json_object);
-
- // Returns true if a pair with the given name was found.
- bool Seek(const char* name);
-
- // Returns true if a syntax error was found.
- bool Error() const { return error_; }
-
- // Returns a pointer to the matching closing brace if the text starts
- // with a valid JSON object. Returns NULL otherwise.
- const char* EndOfObject();
-
- JSONType Type() const;
- const char* ValueChars() const {
- return (Type() != kNone) ? scanner_.TokenChars() : NULL;
- }
- int ValueLen() const {
- return (Type() != kNone) ? scanner_.TokenLen() : 0;
- }
- void GetRawValueChars(char* buf, intptr_t buflen) const;
- void GetDecodedValueChars(char* buf, intptr_t buflen) const;
- bool IsStringLiteral(const char* literal) const {
- return scanner_.IsStringLiteral(literal);
- }
- bool IsTrue() const {
- return scanner_.CurrentToken() == JSONScanner::TokenTrue;
- }
- bool IsFalse() const {
- return scanner_.CurrentToken() == JSONScanner::TokenFalse;
- }
- bool IsNull() const {
- return scanner_.CurrentToken() == JSONScanner::TokenNull;
- }
-
- // Debugging method to check for validity of a JSON message.
- bool CheckMessage();
-
- private:
- void CheckObject();
- void CheckArray();
- void CheckValue();
-
- JSONScanner scanner_;
- const char* json_object_;
- bool error_;
-};
-
-
-// TextBuffer maintains a dynamic character buffer with a printf-style way to
-// append text.
-class TextBuffer : ValueObject {
- public:
- explicit TextBuffer(intptr_t buf_size);
- ~TextBuffer();
-
- intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
- void AddChar(char ch);
- void EscapeAndAddCodeUnit(uint32_t cu);
- void AddString(const char* s);
- void AddEscapedString(const char* s);
-
- void Clear();
-
- char* buf() { return buf_; }
- intptr_t length() { return msg_len_; }
-
- // Steal ownership of the buffer pointer.
- // NOTE: TextBuffer is empty afterwards.
- const char* Steal();
-
- private:
- void EnsureCapacity(intptr_t len);
- char* buf_;
- intptr_t buf_size_;
- intptr_t msg_len_;
-};
-
-} // namespace dart
-
-#endif // PLATFORM_JSON_H_
diff --git a/runtime/platform/platform_headers.gypi b/runtime/platform/platform_headers.gypi
index bf99985..6619720 100644
--- a/runtime/platform/platform_headers.gypi
+++ b/runtime/platform/platform_headers.gypi
@@ -13,8 +13,8 @@
'globals.h',
'hashmap.h',
'inttypes_support_win.h',
- 'json.h',
'memory_sanitizer.h',
+ 'text_buffer.h',
'utils.h',
],
}
diff --git a/runtime/platform/platform_sources.gypi b/runtime/platform/platform_sources.gypi
index 5885f73..7327ad3 100644
--- a/runtime/platform/platform_sources.gypi
+++ b/runtime/platform/platform_sources.gypi
@@ -7,9 +7,9 @@
'sources': [
'assert.cc',
'hashmap.cc',
- 'json.cc',
'floating_point_win.cc',
'signal_blocker.h',
+ 'text_buffer.cc',
'utils.cc',
],
}
diff --git a/runtime/platform/text_buffer.cc b/runtime/platform/text_buffer.cc
new file mode 100644
index 0000000..b9c6ac7
--- /dev/null
+++ b/runtime/platform/text_buffer.cc
@@ -0,0 +1,157 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/text_buffer.h"
+
+#include "platform/assert.h"
+#include "platform/globals.h"
+#include "platform/utils.h"
+#include "vm/os.h"
+
+namespace dart {
+
+TextBuffer::TextBuffer(intptr_t buf_size) {
+ ASSERT(buf_size > 0);
+ buf_ = reinterpret_cast<char*>(malloc(buf_size));
+ buf_size_ = buf_size;
+ Clear();
+}
+
+
+TextBuffer::~TextBuffer() {
+ free(buf_);
+ buf_ = NULL;
+}
+
+
+void TextBuffer::Clear() {
+ msg_len_ = 0;
+ buf_[0] = '\0';
+}
+
+
+const char* TextBuffer::Steal() {
+ const char* r = buf_;
+ buf_ = NULL;
+ buf_size_ = 0;
+ msg_len_ = 0;
+ return r;
+}
+
+
+void TextBuffer::AddChar(char ch) {
+ EnsureCapacity(sizeof(ch));
+ buf_[msg_len_] = ch;
+ msg_len_++;
+ buf_[msg_len_] = '\0';
+}
+
+
+intptr_t TextBuffer::Printf(const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ intptr_t remaining = buf_size_ - msg_len_;
+ ASSERT(remaining >= 0);
+ intptr_t len = OS::VSNPrint(buf_ + msg_len_, remaining, format, args);
+ va_end(args);
+ if (len >= remaining) {
+ EnsureCapacity(len);
+ remaining = buf_size_ - msg_len_;
+ ASSERT(remaining > len);
+ va_list args2;
+ va_start(args2, format);
+ intptr_t len2 = OS::VSNPrint(buf_ + msg_len_, remaining, format, args2);
+ va_end(args2);
+ ASSERT(len == len2);
+ }
+ msg_len_ += len;
+ buf_[msg_len_] = '\0';
+ return len;
+}
+
+
+// Write a UTF-16 code unit so it can be read by a JSON parser in a string
+// literal. Use escape sequences for characters other than printable ASCII.
+void TextBuffer::EscapeAndAddCodeUnit(uint32_t codeunit) {
+ switch (codeunit) {
+ case '"':
+ Printf("%s", "\\\"");
+ break;
+ case '\\':
+ Printf("%s", "\\\\");
+ break;
+ case '/':
+ Printf("%s", "\\/");
+ break;
+ case '\b':
+ Printf("%s", "\\b");
+ break;
+ case '\f':
+ Printf("%s", "\\f");
+ break;
+ case '\n':
+ Printf("%s", "\\n");
+ break;
+ case '\r':
+ Printf("%s", "\\r");
+ break;
+ case '\t':
+ Printf("%s", "\\t");
+ break;
+ default:
+ if (codeunit < 0x20) {
+ // Encode character as \u00HH.
+ uint32_t digit2 = (codeunit >> 4) & 0xf;
+ uint32_t digit3 = (codeunit & 0xf);
+ Printf("\\u00%c%c",
+ digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
+ digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
+ } else if (codeunit > 127) {
+ // Encode character as \uHHHH.
+ uint32_t digit0 = (codeunit >> 12) & 0xf;
+ uint32_t digit1 = (codeunit >> 8) & 0xf;
+ uint32_t digit2 = (codeunit >> 4) & 0xf;
+ uint32_t digit3 = (codeunit & 0xf);
+ Printf("\\u%c%c%c%c",
+ digit0 > 9 ? 'A' + (digit0 - 10) : '0' + digit0,
+ digit1 > 9 ? 'A' + (digit1 - 10) : '0' + digit1,
+ digit2 > 9 ? 'A' + (digit2 - 10) : '0' + digit2,
+ digit3 > 9 ? 'A' + (digit3 - 10) : '0' + digit3);
+ } else {
+ AddChar(codeunit);
+ }
+ }
+}
+
+
+void TextBuffer::AddString(const char* s) {
+ Printf("%s", s);
+}
+
+
+void TextBuffer::AddEscapedString(const char* s) {
+ intptr_t len = strlen(s);
+ for (int i = 0; i < len; i++) {
+ EscapeAndAddCodeUnit(s[i]);
+ }
+}
+
+
+void TextBuffer::EnsureCapacity(intptr_t len) {
+ intptr_t remaining = buf_size_ - msg_len_;
+ if (remaining <= len) {
+ const int kBufferSpareCapacity = 64; // Somewhat arbitrary.
+ // TODO(turnidge): do we need to guard against overflow or other
+ // security issues here? Text buffers are used by the debugger
+ // to send user-controlled data (e.g. values of string variables) to
+ // the debugger front-end.
+ intptr_t new_size = buf_size_ + len + kBufferSpareCapacity;
+ char* new_buf = reinterpret_cast<char*>(realloc(buf_, new_size));
+ ASSERT(new_buf != NULL);
+ buf_ = new_buf;
+ buf_size_ = new_size;
+ }
+}
+
+} // namespace dart
diff --git a/runtime/platform/text_buffer.h b/runtime/platform/text_buffer.h
new file mode 100644
index 0000000..f8f0c2f
--- /dev/null
+++ b/runtime/platform/text_buffer.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef PLATFORM_TEXT_BUFFER_H_
+#define PLATFORM_TEXT_BUFFER_H_
+
+#include "vm/allocation.h"
+#include "vm/globals.h"
+
+namespace dart {
+
+
+// TextBuffer maintains a dynamic character buffer with a printf-style way to
+// append text.
+class TextBuffer : ValueObject {
+ public:
+ explicit TextBuffer(intptr_t buf_size);
+ ~TextBuffer();
+
+ intptr_t Printf(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
+ void AddChar(char ch);
+ void EscapeAndAddCodeUnit(uint32_t cu);
+ void AddString(const char* s);
+ void AddEscapedString(const char* s);
+
+ void Clear();
+
+ char* buf() { return buf_; }
+ intptr_t length() { return msg_len_; }
+
+ // Steal ownership of the buffer pointer.
+ // NOTE: TextBuffer is empty afterwards.
+ const char* Steal();
+
+ private:
+ void EnsureCapacity(intptr_t len);
+ char* buf_;
+ intptr_t buf_size_;
+ intptr_t msg_len_;
+};
+
+} // namespace dart
+
+#endif // PLATFORM_TEXT_BUFFER_H_
diff --git a/runtime/platform/utils.h b/runtime/platform/utils.h
index 54ebf4d..9e4a384 100644
--- a/runtime/platform/utils.h
+++ b/runtime/platform/utils.h
@@ -214,6 +214,8 @@
return true;
#endif
}
+
+ static char* StrError(int err, char* buffer, size_t bufsize);
};
} // namespace dart
diff --git a/runtime/platform/utils_android.h b/runtime/platform/utils_android.h
index 904f6f4..7709442 100644
--- a/runtime/platform/utils_android.h
+++ b/runtime/platform/utils_android.h
@@ -60,6 +60,13 @@
return htole64(value);
}
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+ if (strerror_r(err, buffer, bufsize) != 0) {
+ snprintf(buffer, bufsize, "%s", "strerror_r failed");
+ }
+ return buffer;
+}
+
} // namespace dart
#endif // PLATFORM_UTILS_ANDROID_H_
diff --git a/runtime/platform/utils_linux.h b/runtime/platform/utils_linux.h
index f2af4d1..bb9594f 100644
--- a/runtime/platform/utils_linux.h
+++ b/runtime/platform/utils_linux.h
@@ -60,6 +60,21 @@
return htole64(value);
}
+
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+#if !defined(__GLIBC__) || \
+((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
+ // Use the XSI version.
+ if (strerror_r(err, buffer, bufsize) != 0) {
+ snprintf(buffer, bufsize, "%s", "strerror_r failed");
+ }
+ return buffer;
+#else
+ // Use the GNU specific version.
+ return strerror_r(err, buffer, bufsize);
+#endif
+}
+
} // namespace dart
#endif // PLATFORM_UTILS_LINUX_H_
diff --git a/runtime/platform/utils_macos.h b/runtime/platform/utils_macos.h
index 3fa29849..7c2a966 100644
--- a/runtime/platform/utils_macos.h
+++ b/runtime/platform/utils_macos.h
@@ -60,6 +60,13 @@
return OSSwapHostToLittleInt64(value);
}
+inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
+ if (strerror_r(err, buffer, bufsize) != 0) {
+ snprintf(buffer, bufsize, "%s", "strerror_r failed");
+ }
+ return buffer;
+}
+
} // namespace dart
#endif // PLATFORM_UTILS_MACOS_H_
diff --git a/runtime/tests/vm/dart/data_uri_failures_test.dart b/runtime/tests/vm/dart/data_uri_failures_test.dart
deleted file mode 100644
index 2df3195..0000000
--- a/runtime/tests/vm/dart/data_uri_failures_test.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'data:text/plain;charset=utf-8,foo%28%29%20%3D%3E%2042%3B'; /// wrongmime: ok
-import 'data:;charset=utf-8,foo%28%29%20%3D%3E%2042%3B'; /// nomime: ok
-import 'data:application/dart;charset=utf-16,foo%28%29%20%3D%3E%2042%3B'; /// utf16: runtime error
-import 'data:application/dart,foo%28%29%20%3D%3E%2042%3B'; /// nocharset: ok
-import 'data:application/dart;charset=utf-8,foo?%9g'; /// badencodeddate: runtime error
-import 'data:application/dart;charset=utf-8;base64,Zm9vKCkgPT4gNDI7'; /// base64: ok
-
-main() {
-}
\ No newline at end of file
diff --git a/runtime/tests/vm/dart/data_uri_import_test.dart b/runtime/tests/vm/dart/data_uri_import_test.dart
index 2430b95..8ce4e1a 100644
--- a/runtime/tests/vm/dart/data_uri_import_test.dart
+++ b/runtime/tests/vm/dart/data_uri_import_test.dart
@@ -3,7 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
// foo() => 42;
-import 'data:application/dart;charset=utf-8,foo%28%29%20%3D%3E%2042%3B';
+import 'data:application/dart;charset=utf-8,foo%28%29%20%3D%3E%2042%3B'; /// percentencoded: ok
+import 'data:text/plain;charset=utf-8,foo%28%29%20%3D%3E%2042%3B'; /// wrongmime: ok
+import 'data:;charset=utf-8,foo%28%29%20%3D%3E%2042%3B'; /// nomime: ok
+import 'data:application/dart;charset=utf-16,foo%28%29%20%3D%3E%2042%3B'; /// utf16: runtime error
+import 'data:application/dart,foo%28%29%20%3D%3E%2042%3B'; /// nocharset: ok
+import 'data:application/dart;charset=utf-8,foo?%9g'; /// badencodeddate: runtime error
+import 'data:application/dart;charset=utf-8;base64,Zm9vKCkgPT4gNDI7'; /// base64: ok
import "package:expect/expect.dart";
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 07373d4..faa6779 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -12,13 +12,15 @@
# Flaky on buildbot. Issue 5133 and 10409.
cc/Sleep: Pass, Fail
+dart/data_uri_import_test/none: SkipByDesign
+
[ $mode == debug ]
# This is a benchmark that is not informative in debug mode.
cc/CorelibIsolateStartup: Skip
# Negative tests of VerifiedMemory should crash iff in DEBUG mode.
# TODO(koda): Improve support for negative tests.
-cc/VerifyImplicit_Crash: Crash
-cc/VerifyExplicit_Crash: Crash
+cc/VerifyImplicit_Crash: Crash, Timeout # Timeout: Issue #24596
+cc/VerifyExplicit_Crash: Crash, Timeout # Timeout: Issue #24596
# The following section refers to the dart vm tests which live under
# runtime/tests/vm/dart.
@@ -56,10 +58,9 @@
dart/data_uri*test: Skip
[ $runtime == vm ]
-dart/data_uri_failures_test/wrongmime: RuntimeError, OK # VM is more restrictive than the browser
-dart/data_uri_failures_test/nomime: RuntimeError, OK
-dart/data_uri_failures_test/nocharset: RuntimeError, OK
-dart/data_uri_failures_test/base64: RuntimeError, OK
+dart/data_uri_import_test/wrongmime: RuntimeError, OK # VM is more restrictive than the browser
+dart/data_uri_import_test/nomime: RuntimeError, OK
+dart/data_uri_import_test/nocharset: RuntimeError, OK
[ $arch == mips ]
cc/StaticNonNullSumCallCodegen: Crash, Pass # Issue 17440
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index a187ee8..9320421 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -1625,14 +1625,17 @@
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_RUN(LoadImmediatePPSmall, test) {
- EXPECT_EQ(42, test->InvokeWithCode<int64_t>());
+ EXPECT_EQ(42, test->InvokeWithCodeAndThread<int64_t>());
}
@@ -1667,7 +1670,7 @@
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_RUN(LoadImmediatePPMed2, test) {
- EXPECT_EQ(0x4321f1234124, test->InvokeWithCode<int64_t>());
+ EXPECT_EQ(0x4321f1234124, test->InvokeWithCodeAndThread<int64_t>());
}
@@ -1698,23 +1701,15 @@
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_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_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_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 @@
__ 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_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)));
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 9c4b45d..b3a1d09 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -785,57 +785,29 @@
}
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::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::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::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));
}
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index a78f3ca..eb8219d 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -2021,16 +2021,21 @@
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_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_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_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_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_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_RUN(PackedLogicalNot, test) {
- uint32_t res = test->InvokeWithCode<uint32_t>();
+ uint32_t res = test->InvokeWithCodeAndThread<uint32_t>();
EXPECT_EQ(static_cast<uword>(0x0), res);
}
@@ -3092,8 +3097,7 @@
__ CompareObject(RCX, smi);
__ j(NOT_EQUAL, &fail);
__ movl(RAX, Immediate(1)); // OK
- __ popq(PP); // Restore caller's pool pointer.
- __ LeaveFrame();
+ LeaveTestFrame(assembler);
__ ret();
__ Bind(&fail);
__ movl(RAX, Immediate(0)); // Fail.
@@ -3103,7 +3107,7 @@
ASSEMBLER_TEST_RUN(TestObjectCompare, test) {
- bool res = test->InvokeWithCode<bool>();
+ bool res = test->InvokeWithCodeAndThread<bool>();
EXPECT_EQ(true, res);
}
@@ -3415,10 +3419,13 @@
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 +3435,10 @@
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);
}
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 48bd053..8698e26 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -122,6 +122,16 @@
}
+bool StringInterpolateNode::IsPotentiallyConst() const {
+ for (int i = 0; i < value_->length(); i++) {
+ if (!value_->ElementAt(i)->IsPotentiallyConst()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
bool LiteralNode::IsPotentiallyConst() const {
return true;
}
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 14934fd..0e9b68c 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -92,7 +92,6 @@
#define DECLARE_COMMON_NODE_FUNCTIONS(type) \
virtual void Visit(AstNodeVisitor* visitor); \
virtual const char* PrettyName() const; \
- virtual bool Is##type() const { return true; } \
virtual type* As##type() { return this; }
@@ -107,7 +106,7 @@
intptr_t token_pos() const { return token_pos_; }
#define AST_TYPE_CHECK(BaseName) \
- virtual bool Is##BaseName##Node() const { return false; } \
+ bool Is##BaseName##Node() { return As##BaseName##Node() != NULL; } \
virtual BaseName##Node* As##BaseName##Node() { return NULL; }
FOR_EACH_NODE(AST_TYPE_CHECK)
@@ -411,6 +410,8 @@
ArrayNode* value() const { return value_; }
+ virtual bool IsPotentiallyConst() const;
+
DECLARE_COMMON_NODE_FUNCTIONS(StringInterpolateNode);
private:
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index 1b22bc5..dc2fcdf 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -55,7 +55,7 @@
BENCHMARK(CorelibCompilerStats) {
bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
- CompilerStats* stats = Isolate::Current()->compiler_stats();
+ CompilerStats* stats = thread->isolate()->compiler_stats();
ASSERT(stats != NULL);
stats->EnableBenchmark();
Timer timer(true, "Compiler stats compiling all of Core lib");
@@ -77,7 +77,7 @@
BENCHMARK(CorelibIsolateStartup) {
const int kNumIterations = 1000;
Timer timer(true, "CorelibIsolateStartup");
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Thread::ExitIsolate();
for (int i = 0; i < kNumIterations; i++) {
timer.Start();
@@ -416,7 +416,7 @@
reinterpret_cast<Dart_NativeEntryResolver>(NativeResolver));
EXPECT_VALID(lib);
}
- CompilerStats* stats = Isolate::Current()->compiler_stats();
+ CompilerStats* stats = thread->isolate()->compiler_stats();
ASSERT(stats != NULL);
stats->EnableBenchmark();
Timer timer(true, "Compile all of dart2js benchmark");
@@ -545,7 +545,7 @@
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
- Api::CheckAndFinalizePendingClasses(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
@@ -582,7 +582,7 @@
// Need to load the script into the dart: core library due to
// the import of dart:_internal.
TestCase::LoadCoreTestScript(kScriptChars, NULL);
- Api::CheckAndFinalizePendingClasses(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(thread);
// Write snapshot with object content.
FullSnapshotWriter writer(&vm_isolate_snapshot_buffer,
@@ -623,7 +623,7 @@
"\n";
const intptr_t kLoopCount = 1000000;
TestCase::LoadTestScript(kScriptChars, NULL);
- Api::CheckAndFinalizePendingClasses(Isolate::Current());
+ Api::CheckAndFinalizePendingClasses(thread);
Dart_Isolate isolate = Dart_CurrentIsolate();
Timer timer(true, "Enter and Exit isolate");
timer.Start();
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 5d7bdc39..7596920 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -181,7 +181,6 @@
const Library& lib,
const String& uri) {
Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
const String& part_source = String::Handle(
zone, GetLibrarySource(lib, uri, false));
const String& lib_uri = String::Handle(zone, lib.url());
@@ -201,7 +200,7 @@
const Script& part_script = Script::Handle(
zone, Script::New(part_uri, part_source, RawScript::kSourceTag));
const Error& error = Error::Handle(zone, Compile(lib, part_script));
- return Api::NewHandle(isolate, error.raw());
+ return Api::NewHandle(thread, error.raw());
}
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 03393de..315ce85 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -151,6 +151,7 @@
V(DateNatives_localTimeZoneAdjustmentInSeconds, 0) \
V(AssertionError_throwNew, 2) \
V(Async_rethrow, 2) \
+ V(StackTrace_current, 0) \
V(TypeError_throwNew, 5) \
V(FallThroughError_throwNew, 1) \
V(AbstractClassInstantiationError_throwNew, 2) \
@@ -406,6 +407,7 @@
V(VMService_ListenStream, 1) \
V(VMService_CancelStream, 1) \
V(VMService_RequestAssets, 0) \
+ V(VMService_DecodeAssets, 1) \
class BootstrapNatives : public AllStatic {
public:
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 2aba065..b981608 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -13,7 +13,6 @@
#include "vm/debugger.h"
#include "vm/deopt_instructions.h"
#include "vm/exceptions.h"
-#include "vm/intermediate_language.h"
#include "vm/object_store.h"
#include "vm/message.h"
#include "vm/message_handler.h"
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 3ce52e1..c42072f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -77,6 +77,7 @@
bool Compiler::always_optimize_ = false;
bool Compiler::allow_recompilation_ = true;
+#ifndef DART_PRECOMPILED
// TODO(zerny): Factor out unoptimizing/optimizing pipelines and remove
// separate helpers functions & `optimizing` args.
@@ -315,7 +316,7 @@
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (FLAG_trace_compiler) {
- THR_Print("Compiling Class %s '%s'\n", "", cls.ToCString());
+ THR_Print("Compiling Class '%s'\n", cls.ToCString());
}
// Add the primary class which needs to be parsed to the parse list.
@@ -548,7 +549,9 @@
FlowGraphInliner inliner(flow_graph,
&inline_id_to_function,
- &caller_inline_id);
+ &caller_inline_id,
+ use_speculative_inlining,
+ &inlining_black_list);
inliner.Inline();
// Use lists are maintained and validated by the inliner.
DEBUG_ASSERT(flow_graph->VerifyUseLists());
@@ -1387,24 +1390,6 @@
func.ClearCode();
}
}
-
- // Inner functions get added to the closures array. As part of compilation
- // more closures can be added to the end of the array. Compile all the
- // closures until we have reached the end of the "worklist".
- const GrowableObjectArray& closures =
- GrowableObjectArray::Handle(zone,
- Isolate::Current()->object_store()->closure_functions());
- for (int i = 0; i < closures.Length(); i++) {
- func ^= closures.At(i);
- if ((func.Owner() == cls.raw()) && !func.HasCode()) {
- error = CompileFunction(thread, func);
- if (!error.IsNull()) {
- return error.raw();
- }
- func.ClearICDataArray();
- func.ClearCode();
- }
- }
return error.raw();
}
@@ -1731,9 +1716,7 @@
void BackgroundCompiler::Stop(BackgroundCompiler* task) {
ASSERT(Isolate::Current()->background_compiler() == task);
- if (task == NULL) {
- return;
- }
+ ASSERT(task != NULL);
BackgroundCompilationQueue* function_queue = task->function_queue();
Monitor* queue_monitor = task->queue_monitor_;
@@ -1792,4 +1775,112 @@
}
}
+
+#else // DART_PRECOMPILED
+
+
+DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
+ UNREACHABLE();
+}
+
+
+bool Compiler::IsBackgroundCompilation() {
+ UNREACHABLE();
+ return false;
+}
+
+
+RawError* Compiler::Compile(const Library& library, const Script& script) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+RawError* Compiler::CompileClass(const Class& cls) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+RawError* Compiler::CompileFunction(Thread* thread,
+ const Function& function) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+RawError* Compiler::EnsureUnoptimizedCode(Thread* thread,
+ const Function& function) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+RawError* Compiler::CompileOptimizedFunction(Thread* thread,
+ const Function& function,
+ intptr_t osr_id) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+RawError* Compiler::CompileParsedFunction(
+ ParsedFunction* parsed_function) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+void Compiler::ComputeLocalVarDescriptors(const Code& code) {
+ UNREACHABLE();
+}
+
+
+RawError* Compiler::CompileAllFunctions(const Class& cls) {
+ UNREACHABLE();
+ return Error::null();
+}
+
+
+void Compiler::CompileStaticInitializer(const Field& field) {
+ UNREACHABLE();
+}
+
+
+RawObject* Compiler::EvaluateStaticInitializer(const Field& field) {
+ ASSERT(field.HasPrecompiledInitializer());
+ const Function& initializer =
+ Function::Handle(field.PrecompiledInitializer());
+ return DartEntry::InvokeFunction(initializer, Object::empty_array());
+}
+
+
+
+RawObject* Compiler::ExecuteOnce(SequenceNode* fragment) {
+ UNREACHABLE();
+ return Object::null();
+}
+
+
+void BackgroundCompiler::CompileOptimized(const Function& function) {
+ UNREACHABLE();
+}
+
+
+void BackgroundCompiler::VisitPointers(ObjectPointerVisitor* visitor) {
+ UNREACHABLE();
+}
+
+
+void BackgroundCompiler::Stop(BackgroundCompiler* task) {
+ UNREACHABLE();
+}
+
+
+void BackgroundCompiler::EnsureInit(Thread* thread) {
+ UNREACHABLE();
+}
+
+#endif // DART_PRECOMPILED
+
} // namespace dart
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 61c09a6..5e4f53c 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -19,6 +19,8 @@
DEFINE_FLAG(bool, trace_constant_propagation, false,
"Print constant propagation and useless code elimination.");
+DECLARE_FLAG(bool, fields_may_be_reset);
+
// Quick access to the current zone and isolate.
#define I (isolate())
#define Z (graph_->zone())
@@ -704,14 +706,16 @@
void ConstantPropagator::VisitLoadStaticField(LoadStaticFieldInstr* instr) {
- const Field& field = instr->StaticField();
- ASSERT(field.is_static());
- Instance& obj = Instance::Handle(Z, field.StaticValue());
- if (field.is_final() && (obj.raw() != Object::sentinel().raw()) &&
- (obj.raw() != Object::transition_sentinel().raw())) {
- if (obj.IsSmi() || obj.IsOld()) {
- SetValue(instr, obj);
- return;
+ if (!FLAG_fields_may_be_reset) {
+ const Field& field = instr->StaticField();
+ ASSERT(field.is_static());
+ Instance& obj = Instance::Handle(Z, field.StaticValue());
+ if (field.is_final() && (obj.raw() != Object::sentinel().raw()) &&
+ (obj.raw() != Object::transition_sentinel().raw())) {
+ if (obj.IsSmi() || obj.IsOld()) {
+ SetValue(instr, obj);
+ return;
+ }
}
}
SetValue(instr, non_constant_);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 14ff0e7..eb12276 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -73,8 +73,6 @@
const char* Dart::InitOnce(const uint8_t* vm_isolate_snapshot,
const uint8_t* instructions_snapshot,
Dart_IsolateCreateCallback create,
- Dart_IsolateInterruptCallback interrupt,
- Dart_IsolateUnhandledExceptionCallback unhandled,
Dart_IsolateShutdownCallback shutdown,
Dart_FileOpenCallback file_open,
Dart_FileReadCallback file_read,
@@ -90,11 +88,8 @@
Isolate::SetEntropySourceCallback(entropy_source);
OS::InitOnce();
VirtualMemory::InitOnce();
- Thread::InitOnceBeforeIsolate();
- Thread::EnsureInit();
+ OSThread::InitOnce();
Timeline::InitOnce();
- Thread* thread = Thread::Current();
- thread->set_name("Dart_Initialize");
TimelineDurationScope tds(Timeline::GetVMStream(),
"Dart::InitOnce");
Isolate::InitOnce();
@@ -108,7 +103,6 @@
Metric::InitOnce();
StoreBuffer::InitOnce();
MarkingStack::InitOnce();
- Thread::EnsureInit();
#if defined(USING_SIMULATOR)
Simulator::InitOnce();
@@ -120,8 +114,6 @@
ASSERT(thread_pool_ == NULL);
thread_pool_ = new ThreadPool();
{
- Thread* T = Thread::Current();
- ASSERT(T != NULL);
ASSERT(vm_isolate_ == NULL);
ASSERT(Flags::Initialized());
const bool is_vm_isolate = true;
@@ -137,6 +129,8 @@
ASSERT(vm_isolate_ == Isolate::Current());
ASSERT(vm_isolate_ == Thread::Current()->isolate());
+ Thread* T = Thread::Current();
+ ASSERT(T != NULL);
StackZone zone(T);
HandleScope handle_scope(T);
Object::InitNull(vm_isolate_);
@@ -180,7 +174,9 @@
} else {
Symbols::InitOnce(vm_isolate_);
}
- Thread::InitOnceAfterObjectAndStubCode();
+ // We need to initialize the constants here for the vm isolate thread due to
+ // bootstrapping issues.
+ T->InitVMConstants();
Scanner::InitOnce();
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
// Dart VM requires at least SSE2.
@@ -199,8 +195,6 @@
Thread::ExitIsolate(); // Unregister the VM isolate from this thread.
Isolate::SetCreateCallback(create);
- Isolate::SetInterruptCallback(interrupt);
- Isolate::SetUnhandledExceptionCallback(unhandled);
Isolate::SetShutdownCallback(shutdown);
Service::SetGetServiceAssetsCallback(get_service_assets);
@@ -250,7 +244,6 @@
thread_pool_ = NULL;
// Set the VM isolate as current isolate.
- Thread::EnsureInit();
Thread::EnterIsolate(vm_isolate_);
ShutdownIsolate();
@@ -260,7 +253,12 @@
TargetCPUFeatures::Cleanup();
StoreBuffer::ShutDown();
- Thread::Shutdown();
+ // Delete the current thread's TLS and set it's TLS to null.
+ // If it is the last thread then the destructor would call
+ // OSThread::Cleanup.
+ OSThread* os_thread = OSThread::Current();
+ OSThread::SetCurrent(NULL);
+ delete os_thread;
} else {
// Shutdown the service isolate.
ServiceIsolate::Shutdown();
diff --git a/runtime/vm/dart.h b/runtime/vm/dart.h
index 3eded72..412eef2 100644
--- a/runtime/vm/dart.h
+++ b/runtime/vm/dart.h
@@ -24,8 +24,6 @@
const uint8_t* vm_isolate_snapshot,
const uint8_t* instructions_snapshot,
Dart_IsolateCreateCallback create,
- Dart_IsolateInterruptCallback interrupt,
- Dart_IsolateUnhandledExceptionCallback unhandled,
Dart_IsolateShutdownCallback shutdown,
Dart_FileOpenCallback file_open,
Dart_FileReadCallback file_read,
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 7f71986..5971023 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -64,7 +64,7 @@
DEFINE_FLAG(bool, verify_acquired_data, false,
"Verify correct API acquire/release of typed data.");
-ThreadLocalKey Api::api_native_key_ = OSThread::kUnsetThreadLocalKey;
+ThreadLocalKey Api::api_native_key_ = kUnsetThreadLocalKey;
Dart_Handle Api::true_handle_ = NULL;
Dart_Handle Api::false_handle_ = NULL;
Dart_Handle Api::null_handle_ = NULL;
@@ -174,16 +174,14 @@
return true;
}
Thread* thread = arguments->thread();
- Isolate* isolate = thread->isolate();
- ASSERT(isolate == Isolate::Current());
+ ASSERT(thread == Thread::Current());
*peer = NULL;
REUSABLE_OBJECT_HANDLESCOPE(thread);
Object& obj = thread->ObjectHandle();
obj = arguments->NativeArgAt(arg_index);
if (RawObject::IsStringClassId(obj.GetClassId())) {
- ASSERT(isolate->api_state() &&
- isolate->api_state()->top_scope() != NULL);
- *str = Api::NewHandle(isolate, obj.raw());
+ ASSERT(thread->api_top_scope() != NULL);
+ *str = Api::NewHandle(thread, obj.raw());
return true;
}
if (obj.IsNull()) {
@@ -301,8 +299,8 @@
}
-Heap::Space SpaceForExternal(Isolate* isolate, intptr_t size) {
- Heap* heap = isolate->heap();
+Heap::Space SpaceForExternal(Thread* thread, intptr_t size) {
+ Heap* heap = thread->heap();
// If 'size' would be a significant fraction of new space, then use old.
static const int kExtNewRatio = 16;
if (size > (heap->CapacityInWords(Heap::kNew) * kWordSize) / kExtNewRatio) {
@@ -347,18 +345,8 @@
}
-WeakReferenceSetBuilder* ApiState::NewWeakReferenceSetBuilder() {
- return new WeakReferenceSetBuilder(this);
-}
-
-
-void ApiState::DelayWeakReferenceSet(WeakReferenceSet* reference_set) {
- WeakReferenceSet::Push(reference_set, &delayed_weak_reference_sets_);
-}
-
-
-Dart_Handle Api::InitNewHandle(Isolate* isolate, RawObject* raw) {
- LocalHandles* local_handles = Api::TopScope(isolate)->local_handles();
+Dart_Handle Api::InitNewHandle(Thread* thread, RawObject* raw) {
+ LocalHandles* local_handles = Api::TopScope(thread)->local_handles();
ASSERT(local_handles != NULL);
LocalHandle* ref = local_handles->AllocateHandle();
ref->set_raw(raw);
@@ -366,7 +354,7 @@
}
-Dart_Handle Api::NewHandle(Isolate* isolate, RawObject* raw) {
+Dart_Handle Api::NewHandle(Thread* thread, RawObject* raw) {
if (raw == Object::null()) {
return Null();
}
@@ -376,19 +364,17 @@
if (raw == Bool::False().raw()) {
return False();
}
- return InitNewHandle(isolate, raw);
+ return InitNewHandle(thread, raw);
}
RawObject* Api::UnwrapHandle(Dart_Handle object) {
#if defined(DEBUG)
- ASSERT(Thread::Current()->IsMutatorThread());
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
+ Thread* thread = Thread::Current();
+ ASSERT(thread->IsMutatorThread());
+ ASSERT(thread->isolate() != NULL);
ASSERT(!FLAG_verify_handles ||
- state->IsValidLocalHandle(object) ||
+ thread->IsValidLocalHandle(object) ||
Dart::IsReadOnlyApiHandle(object));
ASSERT(FinalizablePersistentHandle::raw_offset() == 0 &&
PersistentHandle::raw_offset() == 0 &&
@@ -433,7 +419,8 @@
}
-Dart_Handle Api::CheckAndFinalizePendingClasses(Isolate* isolate) {
+Dart_Handle Api::CheckAndFinalizePendingClasses(Thread* thread) {
+ Isolate* isolate = thread->isolate();
if (!isolate->AllowClassFinalization()) {
// Class finalization is blocked for the isolate. Do nothing.
return Api::Success();
@@ -442,7 +429,7 @@
return Api::Success();
}
ASSERT(isolate->object_store()->sticky_error() != Object::null());
- return Api::NewHandle(isolate, isolate->object_store()->sticky_error());
+ return Api::NewHandle(thread, isolate->object_store()->sticky_error());
}
@@ -467,7 +454,7 @@
va_end(args2);
const String& message = String::Handle(Z, String::New(buffer));
- return Api::NewHandle(I, ApiError::New(message));
+ return Api::NewHandle(T, ApiError::New(message));
}
@@ -488,20 +475,18 @@
}
-ApiLocalScope* Api::TopScope(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- ApiLocalScope* scope = state->top_scope();
+ApiLocalScope* Api::TopScope(Thread* thread) {
+ ASSERT(thread != NULL);
+ ApiLocalScope* scope = thread->api_top_scope();
ASSERT(scope != NULL);
return scope;
}
void Api::InitOnce() {
- ASSERT(api_native_key_ == OSThread::kUnsetThreadLocalKey);
+ ASSERT(api_native_key_ == kUnsetThreadLocalKey);
api_native_key_ = OSThread::CreateThreadLocal();
- ASSERT(api_native_key_ != OSThread::kUnsetThreadLocalKey);
+ ASSERT(api_native_key_ != kUnsetThreadLocalKey);
}
@@ -691,8 +676,7 @@
Dart_WeakPersistentHandle handle) {
#if defined(DEBUG)
ApiState* state = Isolate::Current()->api_state();
- ASSERT(state->IsValidWeakPersistentHandle(handle) ||
- state->IsValidPrologueWeakPersistentHandle(handle));
+ ASSERT(state->IsValidWeakPersistentHandle(handle));
#endif
return reinterpret_cast<FinalizablePersistentHandle*>(handle);
}
@@ -710,11 +694,7 @@
(*callback)(isolate->init_callback_data(), object, peer);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- if (handle->IsPrologueWeakPersistent()) {
- state->prologue_weak_persistent_handles().FreeHandle(handle);
- } else {
- state->weak_persistent_handles().FreeHandle(handle);
- }
+ state->weak_persistent_handles().FreeHandle(handle);
}
@@ -764,7 +744,7 @@
const Error& error = Error::Cast(obj);
const char* str = error.ToErrorCString();
intptr_t len = strlen(str) + 1;
- char* str_copy = Api::TopScope(I)->zone()->Alloc<char>(len);
+ char* str_copy = Api::TopScope(T)->zone()->Alloc<char>(len);
strncpy(str_copy, str, len);
// Strip a possible trailing '\n'.
if ((len > 1) && (str_copy[len - 2] == '\n')) {
@@ -789,7 +769,7 @@
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsUnhandledException()) {
const UnhandledException& error = UnhandledException::Cast(obj);
- return Api::NewHandle(I, error.exception());
+ return Api::NewHandle(T, error.exception());
} else if (obj.IsError()) {
return Api::NewError("This error is not an unhandled exception error.");
} else {
@@ -803,7 +783,7 @@
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsUnhandledException()) {
const UnhandledException& error = UnhandledException::Cast(obj);
- return Api::NewHandle(I, error.stacktrace());
+ return Api::NewHandle(T, error.stacktrace());
} else if (obj.IsError()) {
return Api::NewError("This error is not an unhandled exception error.");
} else {
@@ -819,7 +799,7 @@
CHECK_CALLBACK_STATE(T);
const String& message = String::Handle(Z, String::New(error));
- return Api::NewHandle(I, ApiError::New(message));
+ return Api::NewHandle(T, ApiError::New(message));
}
@@ -838,13 +818,12 @@
}
}
const Stacktrace& stacktrace = Stacktrace::Handle(Z);
- return Api::NewHandle(I, UnhandledException::New(obj, stacktrace));
+ return Api::NewHandle(T, UnhandledException::New(obj, stacktrace));
}
DART_EXPORT Dart_Handle Dart_PropagateError(Dart_Handle handle) {
Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
{
const Object& obj = Object::Handle(thread->zone(),
Api::UnwrapHandle(handle));
@@ -862,8 +841,6 @@
}
// Unwind all the API scopes till the exit frame before propagating.
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
const Error* error;
{
// We need to preserve the error object across the destruction of zones
@@ -872,7 +849,7 @@
// handle for it in the surviving zone.
NoSafepointScope no_safepoint;
RawError* raw_error = Api::UnwrapErrorHandle(thread->zone(), handle).raw();
- state->UnwindScopes(thread->top_exit_frame_info());
+ thread->UnwindScopes(thread->top_exit_frame_info());
// Note that thread's zone is different here than at the beginning of this
// function.
error = &Error::Handle(thread->zone(), raw_error);
@@ -897,15 +874,15 @@
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
if (obj.IsString()) {
- return Api::NewHandle(I, obj.raw());
+ return Api::NewHandle(T, obj.raw());
} else if (obj.IsInstance()) {
CHECK_CALLBACK_STATE(T);
const Instance& receiver = Instance::Cast(obj);
- return Api::NewHandle(I, DartLibraryCalls::ToString(receiver));
+ return Api::NewHandle(T, DartLibraryCalls::ToString(receiver));
} else {
CHECK_CALLBACK_STATE(T);
// This is a VM internal object. Call the C++ method of printing.
- return Api::NewHandle(I, String::New(obj.ToCString()));
+ return Api::NewHandle(T, String::New(obj.ToCString()));
}
}
@@ -971,29 +948,32 @@
DART_EXPORT Dart_Handle Dart_HandleFromPersistent(
Dart_PersistentHandle object) {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
PersistentHandle* ref = PersistentHandle::Cast(object);
- return Api::NewHandle(isolate, ref->raw());
+ return Api::NewHandle(thread, ref->raw());
}
DART_EXPORT Dart_Handle Dart_HandleFromWeakPersistent(
Dart_WeakPersistentHandle object) {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
FinalizablePersistentHandle* weak_ref =
FinalizablePersistentHandle::Cast(object);
- return Api::NewHandle(isolate, weak_ref->raw());
+ return Api::NewHandle(thread, weak_ref->raw());
}
DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
ApiState* state = I->api_state();
ASSERT(state != NULL);
const Object& old_ref = Object::Handle(Z, Api::UnwrapHandle(object));
@@ -1006,6 +986,7 @@
DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
Dart_Handle obj2) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
ApiState* state = I->api_state();
ASSERT(state != NULL);
ASSERT(state->IsValidPersistentHandle(obj1));
@@ -1018,7 +999,6 @@
static Dart_WeakPersistentHandle AllocateFinalizableHandle(
Thread* thread,
Dart_Handle object,
- bool is_prologue,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
@@ -1027,7 +1007,6 @@
ref = Api::UnwrapHandle(object);
FinalizablePersistentHandle* finalizable_ref =
FinalizablePersistentHandle::New(thread->isolate(),
- is_prologue,
ref,
peer,
callback,
@@ -1048,26 +1027,6 @@
}
return AllocateFinalizableHandle(thread,
object,
- false,
- peer,
- external_allocation_size,
- callback);
-}
-
-
-DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
- Dart_Handle object,
- void* peer,
- intptr_t external_allocation_size,
- Dart_WeakPersistentHandleFinalizer callback) {
- Thread* thread = Thread::Current();
- CHECK_ISOLATE(thread->isolate());
- if (callback == NULL) {
- return NULL;
- }
- return AllocateFinalizableHandle(thread,
- object,
- true,
peer,
external_allocation_size,
callback);
@@ -1098,81 +1057,7 @@
FinalizablePersistentHandle* weak_ref =
FinalizablePersistentHandle::Cast(object);
weak_ref->EnsureFreeExternal(isolate);
- if (weak_ref->IsPrologueWeakPersistent()) {
- ASSERT(state->IsValidPrologueWeakPersistentHandle(object));
- state->prologue_weak_persistent_handles().FreeHandle(weak_ref);
- } else {
- ASSERT(!state->IsValidPrologueWeakPersistentHandle(object));
- state->weak_persistent_handles().FreeHandle(weak_ref);
- }
-}
-
-
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
- Dart_WeakPersistentHandle object) {
- FinalizablePersistentHandle* weak_ref =
- FinalizablePersistentHandle::Cast(object);
- return weak_ref->IsPrologueWeakPersistent();
-}
-
-
-DART_EXPORT Dart_WeakReferenceSetBuilder Dart_NewWeakReferenceSetBuilder() {
- Isolate* isolate = Isolate::Current();
- CHECK_ISOLATE(isolate);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- return reinterpret_cast<Dart_WeakReferenceSetBuilder>(
- state->NewWeakReferenceSetBuilder());
-}
-
-
-DART_EXPORT Dart_WeakReferenceSet Dart_NewWeakReferenceSet(
- Dart_WeakReferenceSetBuilder set_builder,
- Dart_WeakPersistentHandle key,
- Dart_WeakPersistentHandle value) {
- ASSERT(set_builder != NULL && key != NULL);
- WeakReferenceSetBuilder* builder =
- reinterpret_cast<WeakReferenceSetBuilder*>(set_builder);
- ApiState* state = builder->api_state();
- ASSERT(state == Isolate::Current()->api_state());
- WeakReferenceSet* reference_set = builder->NewWeakReferenceSet();
- reference_set->AppendKey(key);
- if (value != NULL) {
- reference_set->AppendValue(value);
- }
- state->DelayWeakReferenceSet(reference_set);
- return reinterpret_cast<Dart_WeakReferenceSet>(reference_set);
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle key,
- Dart_WeakPersistentHandle value) {
- ASSERT(reference_set != NULL);
- WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
- set->Append(key, value);
- return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendKeyToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle key) {
- ASSERT(reference_set != NULL);
- WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
- set->AppendKey(key);
- return Api::Success();
-}
-
-
-DART_EXPORT Dart_Handle Dart_AppendValueToWeakReferenceSet(
- Dart_WeakReferenceSet reference_set,
- Dart_WeakPersistentHandle value) {
- ASSERT(reference_set != NULL);
- WeakReferenceSet* set = reinterpret_cast<WeakReferenceSet*>(reference_set);
- set->AppendValue(value);
- return Api::Success();
+ state->weak_persistent_handles().FreeHandle(weak_ref);
}
@@ -1217,53 +1102,6 @@
}
-class PrologueWeakVisitor : public HandleVisitor {
- public:
- PrologueWeakVisitor(Thread* thread,
- Dart_GcPrologueWeakHandleCallback callback)
- : HandleVisitor(thread),
- callback_(callback) {
- }
-
-
- void VisitHandle(uword addr) {
- NoSafepointScope no_safepoint;
- FinalizablePersistentHandle* handle =
- reinterpret_cast<FinalizablePersistentHandle*>(addr);
- RawObject* raw_obj = handle->raw();
- if (raw_obj->IsHeapObject()) {
- ASSERT(handle->IsPrologueWeakPersistent());
- ReusableInstanceHandleScope reused_instance_handle(thread());
- Instance& instance = reused_instance_handle.Handle();
- instance ^= reinterpret_cast<RawInstance*>(handle->raw());
- intptr_t num_native_fields = instance.NumNativeFields();
- intptr_t* native_fields = instance.NativeFieldsDataAddr();
- if (native_fields != NULL) {
- callback_(thread()->isolate()->init_callback_data(),
- reinterpret_cast<Dart_WeakPersistentHandle>(addr),
- num_native_fields,
- native_fields);
- }
- }
- }
-
- private:
- Dart_GcPrologueWeakHandleCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(PrologueWeakVisitor);
-};
-
-
-DART_EXPORT Dart_Handle Dart_VisitPrologueWeakHandles(
- Dart_GcPrologueWeakHandleCallback callback) {
- Thread* thread = Thread::Current();
- CHECK_ISOLATE(thread->isolate());
- PrologueWeakVisitor visitor(thread, callback);
- thread->isolate()->VisitPrologueWeakPersistentHandles(&visitor);
- return Api::Success();
-}
-
-
// --- Initialization and Globals ---
DART_EXPORT const char* Dart_VersionString() {
@@ -1286,9 +1124,17 @@
if ((instructions_snapshot != NULL) && !FLAG_precompilation) {
return strdup("Flag --precompilation was not specified.");
}
+ if (interrupt != NULL) {
+ return strdup("Dart_Initialize: "
+ "Setting of interrupt callback is not supported.");
+ }
+ if (unhandled != NULL) {
+ return strdup("Dart_Initialize: "
+ "Setting of unhandled exception callback is not supported.");
+ }
const char* err_msg = Dart::InitOnce(vm_isolate_snapshot,
instructions_snapshot,
- create, interrupt, unhandled, shutdown,
+ create, shutdown,
file_open, file_read, file_write,
file_close, entropy_source,
get_service_assets);
@@ -1365,7 +1211,6 @@
char** error) {
CHECK_NO_ISOLATE(Isolate::Current());
char* isolate_name = BuildIsolateName(script_uri, main);
- Thread::EnsureInit();
// Setup default flags in case none were passed.
Dart_IsolateFlags api_flags;
@@ -1447,11 +1292,11 @@
DART_EXPORT Dart_Handle Dart_DebugName() {
DARTSCOPE(Thread::Current());
- return Api::NewHandle(I, String::New(I->name()));
+ Isolate* I = T->isolate();
+ return Api::NewHandle(T, String::New(I->name()));
}
-
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) {
CHECK_NO_ISOLATE(Isolate::Current());
// TODO(16615): Validate isolate parameter.
@@ -1459,26 +1304,25 @@
if (iso->HasMutatorThread()) {
FATAL("Multiple mutators within one isolate is not supported.");
}
- Thread::EnsureInit();
Thread::EnterIsolate(iso);
}
DART_EXPORT void Dart_ThreadDisableProfiling() {
- Thread* T = Thread::Current();
- if (T == NULL) {
+ OSThread* os_thread = OSThread::Current();
+ if (os_thread == NULL) {
return;
}
- T->DisableThreadInterrupts();
+ os_thread->DisableThreadInterrupts();
}
DART_EXPORT void Dart_ThreadEnableProfiling() {
- Thread* T = Thread::Current();
- if (T == NULL) {
+ OSThread* os_thread = OSThread::Current();
+ if (os_thread == NULL) {
return;
}
- T->EnableThreadInterrupts();
+ os_thread->EnableThreadInterrupts();
}
@@ -1508,7 +1352,7 @@
static uint8_t* ApiReallocate(uint8_t* ptr,
intptr_t old_size,
intptr_t new_size) {
- return Api::TopScope(Isolate::Current())->zone()->Realloc<uint8_t>(
+ return Api::TopScope(Thread::Current())->zone()->Realloc<uint8_t>(
ptr, old_size, new_size);
}
@@ -1520,6 +1364,7 @@
intptr_t* isolate_snapshot_size) {
ASSERT(FLAG_load_deferred_eagerly);
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (vm_isolate_snapshot_buffer != NULL &&
vm_isolate_snapshot_size == NULL) {
RETURN_NULL_ERROR(vm_isolate_snapshot_size);
@@ -1531,7 +1376,7 @@
RETURN_NULL_ERROR(isolate_snapshot_size);
}
// Finalize all classes if needed.
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(state)) {
return state;
}
@@ -1560,6 +1405,7 @@
uint8_t** buffer,
intptr_t* size) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (buffer == NULL) {
RETURN_NULL_ERROR(buffer);
}
@@ -1567,7 +1413,7 @@
RETURN_NULL_ERROR(size);
}
// Finalize all classes if needed.
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(state)) {
return state;
}
@@ -1656,7 +1502,7 @@
DART_EXPORT Dart_Handle Dart_RunLoop() {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
- CHECK_ISOLATE_SCOPE(I);
+ CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
Monitor monitor;
MonitorLocker ml(&monitor);
@@ -1676,7 +1522,7 @@
Thread::EnterIsolate(I);
}
if (I->object_store()->sticky_error() != Object::null()) {
- Dart_Handle error = Api::NewHandle(I, I->object_store()->sticky_error());
+ Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
I->object_store()->clear_sticky_error();
return error;
}
@@ -1689,14 +1535,13 @@
DART_EXPORT Dart_Handle Dart_HandleMessage() {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- CHECK_ISOLATE_SCOPE(isolate);
- CHECK_CALLBACK_STATE(thread);
- if (isolate->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
- Dart_Handle error = Api::NewHandle(isolate,
- isolate->object_store()->sticky_error());
- isolate->object_store()->clear_sticky_error();
+ Thread* T = Thread::Current();
+ Isolate* I = T->isolate();
+ CHECK_API_SCOPE(T);
+ CHECK_CALLBACK_STATE(T);
+ if (I->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
+ Dart_Handle error = Api::NewHandle(T, I->object_store()->sticky_error());
+ I->object_store()->clear_sticky_error();
return error;
}
return Api::Success();
@@ -1704,15 +1549,15 @@
DART_EXPORT bool Dart_HandleServiceMessages() {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- CHECK_ISOLATE_SCOPE(isolate);
- CHECK_CALLBACK_STATE(thread);
+ Thread* T = Thread::Current();
+ Isolate* I = T->isolate();
+ CHECK_API_SCOPE(T);
+ CHECK_CALLBACK_STATE(T);
- ASSERT(isolate->GetAndClearResumeRequest() == false);
+ ASSERT(I->GetAndClearResumeRequest() == false);
MessageHandler::MessageStatus status =
- isolate->message_handler()->HandleOOBMessages();
- bool resume = isolate->GetAndClearResumeRequest();
+ I->message_handler()->HandleOOBMessages();
+ bool resume = I->GetAndClearResumeRequest();
return (status != MessageHandler::kOK) || resume;
}
@@ -1760,7 +1605,7 @@
CURRENT_FUNC,
port_id);
}
- return Api::NewHandle(I, SendPort::New(port_id));
+ return Api::NewHandle(T, SendPort::New(port_id));
}
@@ -1793,34 +1638,30 @@
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- ApiLocalScope* new_scope = state->reusable_scope();
+ ApiLocalScope* new_scope = thread->api_reusable_scope();
if (new_scope == NULL) {
- new_scope = new ApiLocalScope(state->top_scope(),
+ new_scope = new ApiLocalScope(thread->api_top_scope(),
thread->top_exit_frame_info());
ASSERT(new_scope != NULL);
} else {
new_scope->Reinit(thread,
- state->top_scope(),
+ thread->api_top_scope(),
thread->top_exit_frame_info());
- state->set_reusable_scope(NULL);
+ thread->set_api_reusable_scope(NULL);
}
- state->set_top_scope(new_scope); // New scope is now the top scope.
+ thread->set_api_top_scope(new_scope); // New scope is now the top scope.
}
DART_EXPORT void Dart_ExitScope() {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- CHECK_ISOLATE_SCOPE(isolate);
- ApiState* state = isolate->api_state();
- ApiLocalScope* scope = state->top_scope();
- ApiLocalScope* reusable_scope = state->reusable_scope();
- state->set_top_scope(scope->previous()); // Reset top scope to previous.
+ Thread* T = Thread::Current();
+ CHECK_API_SCOPE(T);
+ ApiLocalScope* scope = T->api_top_scope();
+ ApiLocalScope* reusable_scope = T->api_reusable_scope();
+ T->set_api_top_scope(scope->previous()); // Reset top scope to previous.
if (reusable_scope == NULL) {
- scope->Reset(thread); // Reset the old scope which we just exited.
- state->set_reusable_scope(scope);
+ scope->Reset(T); // Reset the old scope which we just exited.
+ T->set_api_reusable_scope(scope);
} else {
ASSERT(reusable_scope != scope);
delete scope;
@@ -1830,11 +1671,9 @@
DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size) {
Zone* zone;
- Isolate* isolate = Isolate::Current();
- if (isolate != NULL) {
- ApiState* state = isolate->api_state();
- if (state == NULL) return NULL;
- ApiLocalScope* scope = state->top_scope();
+ Thread* thread = Thread::Current();
+ if (thread != NULL) {
+ ApiLocalScope* scope = thread->api_top_scope();
zone = scope->zone();
} else {
ApiNativeScope* scope = ApiNativeScope::Current();
@@ -1878,7 +1717,7 @@
*value = Bool::Cast(result).value();
return Api::Success();
} else if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
} else {
return Api::NewError("Expected boolean result from ==");
}
@@ -2053,6 +1892,7 @@
DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
TRACE_API_CALL(CURRENT_FUNC);
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsInstance()) {
const Class& future_class =
@@ -2075,15 +1915,16 @@
DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(instance));
if (obj.IsNull()) {
- return Api::NewHandle(I, I->object_store()->null_type());
+ return Api::NewHandle(T, I->object_store()->null_type());
}
if (!obj.IsInstance()) {
RETURN_TYPE_ERROR(Z, instance, Instance);
}
const Type& type = Type::Handle(Instance::Cast(obj).GetType());
- return Api::NewHandle(I, type.Canonicalize());
+ return Api::NewHandle(T, type.Canonicalize());
}
@@ -2145,19 +1986,19 @@
CHECK_ISOLATE(isolate);
if (Smi::IsValid(value)) {
NOHANDLESCOPE(thread);
- return Api::NewHandle(isolate, Smi::New(static_cast<intptr_t>(value)));
+ return Api::NewHandle(thread, Smi::New(static_cast<intptr_t>(value)));
}
// Slow path for Mints and Bigints.
DARTSCOPE(thread);
CHECK_CALLBACK_STATE(thread);
- return Api::NewHandle(isolate, Integer::New(value));
+ return Api::NewHandle(thread, Integer::New(value));
}
DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, Integer::NewFromUint64(value));
+ return Api::NewHandle(T, Integer::NewFromUint64(value));
}
@@ -2165,7 +2006,7 @@
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
const String& str_obj = String::Handle(Z, String::New(str));
- return Api::NewHandle(I, Integer::New(str_obj));
+ return Api::NewHandle(T, Integer::New(str_obj));
}
@@ -2238,7 +2079,7 @@
static uword BigintAllocate(intptr_t size) {
- return Api::TopScope(Isolate::Current())->zone()->AllocUnsafe(size);
+ return Api::TopScope(Thread::Current())->zone()->AllocUnsafe(size);
}
@@ -2263,7 +2104,7 @@
DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, Double::New(value));
+ return Api::NewHandle(T, Double::New(value));
}
@@ -2334,7 +2175,7 @@
RETURN_NULL_ERROR(str);
}
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, String::New(str));
+ return Api::NewHandle(T, String::New(str));
}
@@ -2350,7 +2191,7 @@
CURRENT_FUNC);
}
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, String::FromUTF8(utf8_array, length));
+ return Api::NewHandle(T, String::FromUTF8(utf8_array, length));
}
@@ -2362,7 +2203,7 @@
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, String::FromUTF16(utf16_array, length));
+ return Api::NewHandle(T, String::FromUTF16(utf16_array, length));
}
@@ -2374,7 +2215,7 @@
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, String::FromUTF32(utf32_array, length));
+ return Api::NewHandle(T, String::FromUTF32(utf32_array, length));
}
@@ -2389,12 +2230,11 @@
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I,
- String::NewExternal(latin1_array,
- length,
- peer,
- cback,
- SpaceForExternal(I, length)));
+ return Api::NewHandle(T, String::NewExternal(latin1_array,
+ length,
+ peer,
+ cback,
+ SpaceForExternal(T, length)));
}
@@ -2409,12 +2249,11 @@
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
intptr_t bytes = length * sizeof(*utf16_array);
- return Api::NewHandle(I,
- String::NewExternal(utf16_array,
- length,
- peer,
- cback,
- SpaceForExternal(I, bytes)));
+ return Api::NewHandle(T, String::NewExternal(utf16_array,
+ length,
+ peer,
+ cback,
+ SpaceForExternal(T, bytes)));
}
@@ -2429,7 +2268,7 @@
RETURN_TYPE_ERROR(Z, object, String);
}
intptr_t string_length = Utf8::Length(str_obj);
- char* res = Api::TopScope(I)->zone()->Alloc<char>(string_length + 1);
+ char* res = Api::TopScope(T)->zone()->Alloc<char>(string_length + 1);
if (res == NULL) {
return Api::NewError("Unable to allocate memory");
}
@@ -2456,7 +2295,7 @@
RETURN_TYPE_ERROR(Z, str, String);
}
intptr_t str_len = Utf8::Length(str_obj);
- *utf8_array = Api::TopScope(I)->zone()->Alloc<uint8_t>(str_len);
+ *utf8_array = Api::TopScope(T)->zone()->Alloc<uint8_t>(str_len);
if (*utf8_array == NULL) {
return Api::NewError("Unable to allocate memory");
}
@@ -2576,7 +2415,7 @@
}
return str;
}
- return Api::NewHandle(I, str_obj.MakeExternal(array, length, peer, cback));
+ return Api::NewHandle(T, str_obj.MakeExternal(array, length, peer, cback));
}
@@ -2610,7 +2449,7 @@
DARTSCOPE(Thread::Current());
CHECK_LENGTH(length, Array::kMaxElements);
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, Array::New(length));
+ return Api::NewHandle(T, Array::New(length));
}
@@ -2684,17 +2523,17 @@
return Api::NewError("Length of List object is greater than the "
"maximum value that 'len' parameter can hold");
} else if (retval.IsError()) {
- return Api::NewHandle(I, retval.raw());
+ return Api::NewHandle(T, retval.raw());
} else {
return Api::NewError("Length of List object is not an integer");
}
}
-#define GET_LIST_ELEMENT(isolate, type, obj, index) \
+#define GET_LIST_ELEMENT(thread, type, obj, index) \
const type& array_obj = type::Cast(obj); \
if ((index >= 0) && (index < array_obj.Length())) { \
- return Api::NewHandle(isolate, array_obj.At(index)); \
+ return Api::NewHandle(thread, array_obj.At(index)); \
} \
return Api::NewError("Invalid index passed in to access list element"); \
@@ -2703,9 +2542,9 @@
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
if (obj.IsArray()) {
- GET_LIST_ELEMENT(I, Array, obj, index);
+ GET_LIST_ELEMENT(T, Array, obj, index);
} else if (obj.IsGrowableObjectArray()) {
- GET_LIST_ELEMENT(I, GrowableObjectArray, obj, index);
+ GET_LIST_ELEMENT(T, GrowableObjectArray, obj, index);
} else if (obj.IsError()) {
return list;
} else {
@@ -2713,7 +2552,7 @@
// Check and handle a dart object that implements the List interface.
const Instance& instance = Instance::Handle(Z, GetListInstance(Z, obj));
if (!instance.IsNull()) {
- return Api::NewHandle(I, Send1Arg(
+ return Api::NewHandle(T, Send1Arg(
instance,
Symbols::IndexToken(),
Instance::Handle(Z, Integer::New(index))));
@@ -2723,11 +2562,11 @@
}
-#define GET_LIST_RANGE(isolate, type, obj, offset, length) \
+#define GET_LIST_RANGE(thread, type, obj, offset, length) \
const type& array_obj = type::Cast(obj); \
if ((offset >= 0) && (offset + length <= array_obj.Length())) { \
for (intptr_t index = 0; index < length; ++index) { \
- result[index] = Api::NewHandle(isolate, array_obj.At(index + offset)); \
+ result[index] = Api::NewHandle(thread, array_obj.At(index + offset)); \
} \
return Api::Success(); \
} \
@@ -2744,9 +2583,9 @@
}
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(list));
if (obj.IsArray()) {
- GET_LIST_RANGE(I, Array, obj, offset, length);
+ GET_LIST_RANGE(T, Array, obj, offset, length);
} else if (obj.IsGrowableObjectArray()) {
- GET_LIST_RANGE(I, GrowableObjectArray, obj, offset, length);
+ GET_LIST_RANGE(T, GrowableObjectArray, obj, offset, length);
} else if (obj.IsError()) {
return list;
} else {
@@ -2768,8 +2607,8 @@
for (intptr_t i = 0; i < length; ++i) {
index = Integer::New(i);
args.SetAt(1, index);
- Dart_Handle value = Api::NewHandle(I,
- DartEntry::InvokeFunction(function, args));
+ Dart_Handle value = Api::NewHandle(
+ T, DartEntry::InvokeFunction(function, args));
if (::Dart_IsError(value))
return value;
result[i] = value;
@@ -2831,8 +2670,8 @@
args.SetAt(0, instance);
args.SetAt(1, index_obj);
args.SetAt(2, value_obj);
- return Api::NewHandle(I, DartEntry::InvokeFunction(function,
- args));
+ return Api::NewHandle(
+ T, DartEntry::InvokeFunction(function, args));
}
}
return Api::NewError("Object does not implement the 'List' interface");
@@ -2849,7 +2688,6 @@
static RawObject* ThrowArgumentError(const char* exception_message) {
Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
// Lookup the class ArgumentError in dart:core.
const String& lib_url = String::Handle(String::New("dart:core"));
@@ -2898,13 +2736,11 @@
}
// Unwind all the API scopes till the exit frame before throwing an
// exception.
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
const Instance* saved_exception;
{
NoSafepointScope no_safepoint;
RawInstance* raw_exception = exception.raw();
- state->UnwindScopes(thread->top_exit_frame_info());
+ thread->UnwindScopes(thread->top_exit_frame_info());
saved_exception = &Instance::Handle(raw_exception);
}
Exceptions::Throw(thread, *saved_exception);
@@ -2921,8 +2757,8 @@
for (int i = 0; i < length; i++) { \
element = array.At(offset + i); \
if (!element.IsInteger()) { \
- return Api::NewHandle(I, \
- ThrowArgumentError("List contains non-int elements")); \
+ return Api::NewHandle( \
+ T, ThrowArgumentError("List contains non-int elements")); \
\
} \
const Integer& integer = Integer::Cast(element); \
@@ -3026,7 +2862,7 @@
args.SetAt(1, intobj);
result = DartEntry::InvokeFunction(function, args);
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
if (!result.IsInteger()) {
return Api::NewError("%s expects the argument 'list' to be "
@@ -3115,7 +2951,7 @@
const Object& result = Object::Handle(Z,
DartEntry::InvokeFunction(function, args));
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
}
return Api::Success();
@@ -3137,8 +2973,8 @@
if (!(key_obj.IsInstance() || key_obj.IsNull())) {
return Api::NewError("Key is not an instance");
}
- return Api::NewHandle(I,
- Send1Arg(instance, Symbols::IndexToken(), Instance::Cast(key_obj)));
+ return Api::NewHandle(
+ T, Send1Arg(instance, Symbols::IndexToken(), Instance::Cast(key_obj)));
}
return Api::NewError("Object does not implement the 'Map' interface");
}
@@ -3154,7 +2990,7 @@
if (!(key_obj.IsInstance() || key_obj.IsNull())) {
return Api::NewError("Key is not an instance");
}
- return Api::NewHandle(I, Send1Arg(
+ return Api::NewHandle(T, Send1Arg(
instance,
String::Handle(Z, String::New("containsKey")),
Instance::Cast(key_obj)));
@@ -3172,9 +3008,9 @@
const Object& iterator = Object::Handle(Send0Arg(
instance, String::Handle(Z, String::New("get:keys"))));
if (!iterator.IsInstance()) {
- return Api::NewHandle(I, iterator.raw());
+ return Api::NewHandle(T, iterator.raw());
}
- return Api::NewHandle(I, Send0Arg(
+ return Api::NewHandle(T, Send0Arg(
Instance::Cast(iterator),
String::Handle(String::New("toList"))));
}
@@ -3311,7 +3147,6 @@
static Dart_Handle NewByteData(Thread* thread, intptr_t length) {
CHECK_LENGTH(length, TypedData::MaxElements(kTypedDataInt8ArrayCid));
- Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
Object& result = Object::Handle(zone);
result = GetByteDataConstructor(thread, Symbols::ByteDataDot(), 1);
@@ -3329,22 +3164,21 @@
// Invoke the constructor and return the new object.
result = DartEntry::InvokeFunction(factory, args);
ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
- return Api::NewHandle(isolate, result.raw());
+ return Api::NewHandle(thread, result.raw());
}
-static Dart_Handle NewTypedData(Isolate* isolate,
+static Dart_Handle NewTypedData(Thread* thread,
intptr_t cid,
intptr_t length) {
CHECK_LENGTH(length, TypedData::MaxElements(cid));
- return Api::NewHandle(isolate, TypedData::New(cid, length));
+ return Api::NewHandle(thread, TypedData::New(cid, length));
}
static Dart_Handle NewExternalTypedData(
Thread* thread, intptr_t cid, void* data, intptr_t length) {
CHECK_LENGTH(length, ExternalTypedData::MaxElements(cid));
- Isolate* isolate = thread->isolate();
Zone* zone = thread->zone();
intptr_t bytes = length * ExternalTypedData::ElementSizeInBytes(cid);
const ExternalTypedData& result = ExternalTypedData::Handle(
@@ -3352,15 +3186,14 @@
ExternalTypedData::New(cid,
reinterpret_cast<uint8_t*>(data),
length,
- SpaceForExternal(isolate, bytes)));
- return Api::NewHandle(isolate, result.raw());
+ SpaceForExternal(thread, bytes)));
+ return Api::NewHandle(thread, result.raw());
}
static Dart_Handle NewExternalByteData(
Thread* thread, void* data, intptr_t length) {
Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
Dart_Handle ext_data = NewExternalTypedData(
thread, kExternalTypedDataUint8ArrayCid, data, length);
if (::Dart_IsError(ext_data)) {
@@ -3390,7 +3223,7 @@
// Invoke the constructor and return the new object.
result = DartEntry::InvokeFunction(factory, args);
ASSERT(result.IsNull() || result.IsInstance() || result.IsError());
- return Api::NewHandle(isolate, result.raw());
+ return Api::NewHandle(thread, result.raw());
}
@@ -3402,29 +3235,29 @@
case Dart_TypedData_kByteData :
return NewByteData(T, length);
case Dart_TypedData_kInt8 :
- return NewTypedData(I, kTypedDataInt8ArrayCid, length);
+ return NewTypedData(T, kTypedDataInt8ArrayCid, length);
case Dart_TypedData_kUint8 :
- return NewTypedData(I, kTypedDataUint8ArrayCid, length);
+ return NewTypedData(T, kTypedDataUint8ArrayCid, length);
case Dart_TypedData_kUint8Clamped :
- return NewTypedData(I, kTypedDataUint8ClampedArrayCid, length);
+ return NewTypedData(T, kTypedDataUint8ClampedArrayCid, length);
case Dart_TypedData_kInt16 :
- return NewTypedData(I, kTypedDataInt16ArrayCid, length);
+ return NewTypedData(T, kTypedDataInt16ArrayCid, length);
case Dart_TypedData_kUint16 :
- return NewTypedData(I, kTypedDataUint16ArrayCid, length);
+ return NewTypedData(T, kTypedDataUint16ArrayCid, length);
case Dart_TypedData_kInt32 :
- return NewTypedData(I, kTypedDataInt32ArrayCid, length);
+ return NewTypedData(T, kTypedDataInt32ArrayCid, length);
case Dart_TypedData_kUint32 :
- return NewTypedData(I, kTypedDataUint32ArrayCid, length);
+ return NewTypedData(T, kTypedDataUint32ArrayCid, length);
case Dart_TypedData_kInt64 :
- return NewTypedData(I, kTypedDataInt64ArrayCid, length);
+ return NewTypedData(T, kTypedDataInt64ArrayCid, length);
case Dart_TypedData_kUint64 :
- return NewTypedData(I, kTypedDataUint64ArrayCid, length);
+ return NewTypedData(T, kTypedDataUint64ArrayCid, length);
case Dart_TypedData_kFloat32 :
- return NewTypedData(I, kTypedDataFloat32ArrayCid, length);
+ return NewTypedData(T, kTypedDataFloat32ArrayCid, length);
case Dart_TypedData_kFloat64 :
- return NewTypedData(I, kTypedDataFloat64ArrayCid, length);
+ return NewTypedData(T, kTypedDataFloat64ArrayCid, length);
case Dart_TypedData_kFloat32x4:
- return NewTypedData(I, kTypedDataFloat32x4ArrayCid, length);
+ return NewTypedData(T, kTypedDataFloat32x4ArrayCid, length);
default:
return Api::NewError("%s expects argument 'type' to be of 'TypedData'",
CURRENT_FUNC);
@@ -3447,41 +3280,41 @@
case Dart_TypedData_kByteData:
return NewExternalByteData(T, data, length);
case Dart_TypedData_kInt8:
- return NewExternalTypedData(T,
- kExternalTypedDataInt8ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataInt8ArrayCid, data, length);
case Dart_TypedData_kUint8:
- return NewExternalTypedData(T,
- kExternalTypedDataUint8ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataUint8ArrayCid, data, length);
case Dart_TypedData_kUint8Clamped:
- return NewExternalTypedData(T,
- kExternalTypedDataUint8ClampedArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataUint8ClampedArrayCid, data, length);
case Dart_TypedData_kInt16:
- return NewExternalTypedData(T,
- kExternalTypedDataInt16ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataInt16ArrayCid, data, length);
case Dart_TypedData_kUint16:
- return NewExternalTypedData(T,
- kExternalTypedDataUint16ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataUint16ArrayCid, data, length);
case Dart_TypedData_kInt32:
- return NewExternalTypedData(T,
- kExternalTypedDataInt32ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataInt32ArrayCid, data, length);
case Dart_TypedData_kUint32:
- return NewExternalTypedData(T,
- kExternalTypedDataUint32ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataUint32ArrayCid, data, length);
case Dart_TypedData_kInt64:
- return NewExternalTypedData(T,
- kExternalTypedDataInt64ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataInt64ArrayCid, data, length);
case Dart_TypedData_kUint64:
- return NewExternalTypedData(T,
- kExternalTypedDataUint64ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataUint64ArrayCid, data, length);
case Dart_TypedData_kFloat32:
- return NewExternalTypedData(T,
- kExternalTypedDataFloat32ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataFloat32ArrayCid, data, length);
case Dart_TypedData_kFloat64:
- return NewExternalTypedData(T,
- kExternalTypedDataFloat64ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataFloat64ArrayCid, data, length);
case Dart_TypedData_kFloat32x4:
- return NewExternalTypedData(T,
- kExternalTypedDataFloat32x4ArrayCid, data, length);
+ return NewExternalTypedData(
+ T, kExternalTypedDataFloat32x4ArrayCid, data, length);
default:
return Api::NewError("%s expects argument 'type' to be of"
" 'external TypedData'", CURRENT_FUNC);
@@ -3537,7 +3370,7 @@
// Invoke the factory constructor and return the new object.
result = DartEntry::InvokeFunction(factory, args);
ASSERT(result.IsInstance() || result.IsNull() || result.IsError());
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
@@ -3579,6 +3412,7 @@
void** data,
intptr_t* len) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
intptr_t class_id = Api::ClassId(object);
if (!RawObject::IsExternalTypedDataClassId(class_id) &&
!RawObject::IsTypedDataViewClassId(class_id) &&
@@ -3668,6 +3502,7 @@
DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
intptr_t class_id = Api::ClassId(object);
if (!RawObject::IsExternalTypedDataClassId(class_id) &&
!RawObject::IsTypedDataViewClassId(class_id) &&
@@ -3704,7 +3539,7 @@
}
const Instance& instance = Api::UnwrapInstanceHandle(zone, object);
ASSERT(!instance.IsNull());
- return Api::NewHandle(isolate, ByteBuffer::Data(instance));
+ return Api::NewHandle(thread, ByteBuffer::Data(instance));
}
@@ -3785,11 +3620,6 @@
CURRENT_FUNC);
}
Class& cls = Class::Handle(Z, type_obj.type_class());
-#if defined(DEBUG)
- if (!cls.is_allocated() && Dart::IsRunningPrecompiledCode()) {
- return Api::NewError("Precompilation dropped '%s'", cls.ToCString());
- }
-#endif
TypeArguments& type_arguments =
TypeArguments::Handle(Z, type_obj.arguments());
@@ -3815,7 +3645,7 @@
constr_name,
number_of_arguments);
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
ASSERT(result.IsFunction());
Function& constructor = Function::Handle(Z);
@@ -3828,7 +3658,7 @@
constructor = constructor.RedirectionTarget();
if (constructor.IsNull()) {
ASSERT(redirect_type.IsMalformed());
- return Api::NewHandle(I, redirect_type.error());
+ return Api::NewHandle(T, redirect_type.error());
}
if (!redirect_type.IsInstantiated()) {
@@ -3838,7 +3668,7 @@
redirect_type ^= redirect_type.InstantiateFrom(type_arguments,
&bound_error);
if (!bound_error.IsNull()) {
- return Api::NewHandle(I, bound_error.raw());
+ return Api::NewHandle(T, bound_error.raw());
}
redirect_type ^= redirect_type.Canonicalize();
}
@@ -3849,6 +3679,11 @@
cls = type_obj.type_class();
}
if (constructor.IsGenerativeConstructor()) {
+#if defined(DEBUG)
+ if (!cls.is_allocated() && Dart::IsRunningPrecompiledCode()) {
+ return Api::NewError("Precompilation dropped '%s'", cls.ToCString());
+ }
+#endif
// Create the new object.
new_object = Instance::New(cls);
}
@@ -3877,7 +3712,7 @@
argument = Api::UnwrapHandle(arguments[i]);
if (!argument.IsNull() && !argument.IsInstance()) {
if (argument.IsError()) {
- return Api::NewHandle(I, argument.raw());
+ return Api::NewHandle(T, argument.raw());
} else {
return Api::NewError(
"%s expects arguments[%d] to be an Instance handle.",
@@ -3890,7 +3725,7 @@
// Invoke the constructor and return the new object.
result = DartEntry::InvokeFunction(constructor, args);
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
if (constructor.IsGenerativeConstructor()) {
@@ -3899,7 +3734,7 @@
ASSERT(result.IsNull() || result.IsInstance());
new_object ^= result.raw();
}
- return Api::NewHandle(I, new_object.raw());
+ return Api::NewHandle(T, new_object.raw());
}
@@ -3948,9 +3783,9 @@
const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
// An error occurred, return error object.
- return Api::NewHandle(I, error.raw());
+ return Api::NewHandle(T, error.raw());
}
- return Api::NewHandle(I, AllocateObject(T, cls));
+ return Api::NewHandle(T, AllocateObject(T, cls));
}
@@ -3978,7 +3813,7 @@
const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
// An error occurred, return error object.
- return Api::NewHandle(I, error.raw());
+ return Api::NewHandle(T, error.raw());
}
if (num_native_fields != cls.num_native_fields()) {
return Api::NewError(
@@ -3987,7 +3822,7 @@
}
const Instance& instance = Instance::Handle(Z, AllocateObject(T, cls));
instance.SetNativeFields(num_native_fields, native_fields);
- return Api::NewHandle(I, instance.raw());
+ return Api::NewHandle(T, instance.raw());
}
@@ -3997,7 +3832,6 @@
int extra_args,
Array* args) {
Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
// Check for malformed arguments in the arguments list.
*args = Array::New(num_args + extra_args);
Object& arg = Object::Handle(zone);
@@ -4006,7 +3840,7 @@
if (!arg.IsNull() && !arg.IsInstance()) {
*args = Array::null();
if (arg.IsError()) {
- return Api::NewHandle(isolate, arg.raw());
+ return Api::NewHandle(thread, arg.raw());
} else {
return Api::NewError(
"%s expects arguments[%d] to be an Instance handle.",
@@ -4076,17 +3910,17 @@
}
Dart_Handle result;
Array& args = Array::Handle(Z);
- result = SetupArguments(T,
- number_of_arguments, arguments, extra_args, &args);
+ result = SetupArguments(
+ T, number_of_arguments, arguments, extra_args, &args);
if (!::Dart_IsError(result)) {
args.SetAt(0, instance);
args.SetAt(1, Smi::Handle(Z, Smi::New(Function::kCtorPhaseAll)));
const Object& retval = Object::Handle(Z,
DartEntry::InvokeFunction(constructor, args));
if (retval.IsError()) {
- result = Api::NewHandle(I, retval.raw());
+ result = Api::NewHandle(T, retval.raw());
} else {
- result = Api::NewHandle(I, instance.raw());
+ result = Api::NewHandle(T, instance.raw());
}
}
return result;
@@ -4142,7 +3976,7 @@
// Setup args and check for malformed arguments in the arguments list.
result = SetupArguments(T, number_of_arguments, arguments, 0, &args);
if (!::Dart_IsError(result)) {
- result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+ result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
}
return result;
} else if (obj.IsNull() || obj.IsInstance()) {
@@ -4166,7 +4000,7 @@
args.SetAt(0, instance);
const Array& args_descriptor =
Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
- result = Api::NewHandle(I,
+ result = Api::NewHandle(T,
DartEntry::InvokeNoSuchMethod(instance,
function_name,
args,
@@ -4178,7 +4012,7 @@
result = SetupArguments(T, number_of_arguments, arguments, 1, &args);
if (!::Dart_IsError(result)) {
args.SetAt(0, instance);
- result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+ result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
}
return result;
} else if (obj.IsLibrary()) {
@@ -4213,7 +4047,7 @@
// Setup args and check for malformed arguments in the arguments list.
result = SetupArguments(T, number_of_arguments, arguments, 0, &args);
if (!::Dart_IsError(result)) {
- result = Api::NewHandle(I, DartEntry::InvokeFunction(function, args));
+ result = Api::NewHandle(T, DartEntry::InvokeFunction(function, args));
}
return result;
} else {
@@ -4251,7 +4085,7 @@
args.SetAt(i + 1, obj);
}
// Now try to invoke the closure.
- return Api::NewHandle(I, DartEntry::InvokeClosure(args));
+ return Api::NewHandle(T, DartEntry::InvokeClosure(args));
}
@@ -4289,10 +4123,10 @@
if (!getter.IsNull()) {
// Invoke the getter and return the result.
- return Api::NewHandle(I,
- DartEntry::InvokeFunction(getter, Object::empty_array()));
+ return Api::NewHandle(
+ T, DartEntry::InvokeFunction(getter, Object::empty_array()));
} else if (!field.IsNull()) {
- return Api::NewHandle(I, field.StaticValue());
+ return Api::NewHandle(T, field.StaticValue());
} else {
return Api::NewError("%s: did not find static field '%s'.",
CURRENT_FUNC, field_name.ToCString());
@@ -4320,13 +4154,12 @@
if (getter.IsNull()) {
const Array& args_descriptor =
Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
- return Api::NewHandle(I,
- DartEntry::InvokeNoSuchMethod(instance,
- getter_name,
- args,
- args_descriptor));
+ return Api::NewHandle(T, DartEntry::InvokeNoSuchMethod(instance,
+ getter_name,
+ args,
+ args_descriptor));
}
- return Api::NewHandle(I, DartEntry::InvokeFunction(getter, args));
+ return Api::NewHandle(T, DartEntry::InvokeFunction(getter, args));
} else if (obj.IsLibrary()) {
// To access a top-level we may need to use the Field or the
@@ -4355,11 +4188,11 @@
if (!getter.IsNull()) {
// Invoke the getter and return the result.
- return Api::NewHandle(I,
- DartEntry::InvokeFunction(getter, Object::empty_array()));
+ return Api::NewHandle(
+ T, DartEntry::InvokeFunction(getter, Object::empty_array()));
}
if (!field.IsNull()) {
- return Api::NewHandle(I, field.StaticValue());
+ return Api::NewHandle(T, field.StaticValue());
}
return Api::NewError("%s: did not find top-level variable '%s'.",
CURRENT_FUNC, field_name.ToCString());
@@ -4424,7 +4257,7 @@
const Object& result = Object::Handle(Z,
DartEntry::InvokeFunction(setter, args));
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
} else {
return Api::Success();
}
@@ -4469,12 +4302,12 @@
if (setter.IsNull()) {
const Array& args_descriptor =
Array::Handle(Z, ArgumentsDescriptor::New(args.Length()));
- return Api::NewHandle(I, DartEntry::InvokeNoSuchMethod(instance,
+ return Api::NewHandle(T, DartEntry::InvokeNoSuchMethod(instance,
setter_name,
args,
args_descriptor));
}
- return Api::NewHandle(I, DartEntry::InvokeFunction(setter, args));
+ return Api::NewHandle(T, DartEntry::InvokeFunction(setter, args));
} else if (obj.IsLibrary()) {
// To access a top-level we may need to use the Field or the
@@ -4502,7 +4335,7 @@
const Object& result =
Object::Handle(Z, DartEntry::InvokeFunction(setter, args));
if (result.IsError()) {
- return Api::NewHandle(I, result.raw());
+ return Api::NewHandle(T, result.raw());
}
return Api::Success();
}
@@ -4548,14 +4381,12 @@
// Unwind all the API scopes till the exit frame before throwing an
// exception.
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
const Instance* saved_exception;
{
NoSafepointScope no_safepoint;
RawInstance* raw_exception =
Api::UnwrapInstanceHandle(zone, exception).raw();
- state->UnwindScopes(thread->top_exit_frame_info());
+ thread->UnwindScopes(thread->top_exit_frame_info());
saved_exception = &Instance::Handle(raw_exception);
}
Exceptions::Throw(thread, *saved_exception);
@@ -4588,8 +4419,6 @@
// Unwind all the API scopes till the exit frame before throwing an
// exception.
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
const Instance* saved_exception;
const Stacktrace* saved_stacktrace;
{
@@ -4598,7 +4427,7 @@
Api::UnwrapInstanceHandle(zone, exception).raw();
RawStacktrace* raw_stacktrace =
Api::UnwrapStacktraceHandle(zone, stacktrace).raw();
- state->UnwindScopes(thread->top_exit_frame_info());
+ thread->UnwindScopes(thread->top_exit_frame_info());
saved_exception = &Instance::Handle(raw_exception);
saved_stacktrace = &Stacktrace::Handle(raw_stacktrace);
}
@@ -4634,7 +4463,7 @@
return Api::NewError(
"Unable to create native wrapper class : already exists");
}
- return Api::NewHandle(I, cls.RareType());
+ return Api::NewHandle(T, cls.RareType());
}
@@ -4814,12 +4643,10 @@
}
case Dart_NativeArgument_kInstance: {
- Isolate* isolate = arguments->thread()->isolate();
- ASSERT(isolate == Isolate::Current());
- ASSERT(isolate->api_state() &&
- isolate->api_state()->top_scope() != NULL);
- native_value->as_instance =
- Api::NewHandle(isolate, arguments->NativeArgAt(arg_index));
+ ASSERT(arguments->thread() == Thread::Current());
+ ASSERT(arguments->thread()->api_top_scope() != NULL);
+ native_value->as_instance = Api::NewHandle(
+ arguments->thread(), arguments->NativeArgAt(arg_index));
break;
}
@@ -4841,7 +4668,7 @@
"%s: argument 'index' out of range. Expected 0..%d but saw %d.",
CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
}
- return Api::NewHandle(arguments->thread()->isolate(),
+ return Api::NewHandle(arguments->thread(),
arguments->NativeArgAt(index));
}
@@ -4978,8 +4805,7 @@
Isolate* isolate = arguments->thread()->isolate();
ASSERT(isolate == Isolate::Current());
ASSERT(isolate->api_state() != NULL &&
- (isolate->api_state()->IsValidWeakPersistentHandle(rval) ||
- isolate->api_state()->IsValidPrologueWeakPersistentHandle(rval)));
+ (isolate->api_state()->IsValidWeakPersistentHandle(rval)));
#endif
Api::SetWeakHandleReturnValue(arguments, rval);
}
@@ -4992,7 +4818,7 @@
Dart_EnvironmentCallback callback = isolate->environment_callback();
String& result = String::Handle(thread->zone());
if (callback != NULL) {
- Dart_Handle response = callback(Api::NewHandle(isolate, name.raw()));
+ Dart_Handle response = callback(Api::NewHandle(thread, name.raw()));
if (::Dart_IsString(response)) {
result ^= Api::UnwrapHandle(response);
} else if (::Dart_IsError(response)) {
@@ -5086,9 +4912,9 @@
const Error& error =
Error::Handle(thread->zone(), Compiler::Compile(lib, script));
if (error.IsNull()) {
- *result = Api::NewHandle(thread->isolate(), lib.raw());
+ *result = Api::NewHandle(thread, lib.raw());
} else {
- *result = Api::NewHandle(thread->isolate(), error.raw());
+ *result = Api::NewHandle(thread, error.raw());
// Compilation errors are not Dart instances, so just mark the library
// as having failed to load without providing an error instance.
lib.SetLoadError(Object::null_instance());
@@ -5101,6 +4927,7 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const String& url_str = Api::UnwrapStringHandle(Z, url);
if (url_str.IsNull()) {
RETURN_TYPE_ERROR(Z, url, String);
@@ -5145,6 +4972,7 @@
DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer,
intptr_t buffer_len) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
StackZone zone(T);
if (buffer == NULL) {
RETURN_NULL_ERROR(buffer);
@@ -5174,19 +5002,20 @@
ScriptSnapshotReader reader(snapshot->content(), snapshot->length(), T);
const Object& tmp = Object::Handle(Z, reader.ReadScriptSnapshot());
if (tmp.IsError()) {
- return Api::NewHandle(I, tmp.raw());
+ return Api::NewHandle(T, tmp.raw());
}
library ^= tmp.raw();
library.set_debuggable(true);
I->object_store()->set_root_library(library);
- return Api::NewHandle(I, library.raw());
+ return Api::NewHandle(T, library.raw());
}
DART_EXPORT Dart_Handle Dart_RootLibrary() {
- Isolate* isolate = Isolate::Current();
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
- return Api::NewHandle(isolate, isolate->object_store()->root_library());
+ return Api::NewHandle(thread, isolate->object_store()->root_library());
}
@@ -5220,7 +5049,7 @@
return Api::NewError("Class '%s' not found in library '%s'.",
cls_name.ToCString(), lib_name.ToCString());
}
- return Api::NewHandle(I, cls.RareType());
+ return Api::NewHandle(T, cls.RareType());
}
@@ -5255,7 +5084,7 @@
return Api::NewError("Invalid number of type arguments specified, "
"got %" Pd " expected 0", number_of_type_arguments);
}
- return Api::NewHandle(I, Type::NewNonParameterizedType(cls));
+ return Api::NewHandle(T, Type::NewNonParameterizedType(cls));
}
intptr_t num_expected_type_arguments = cls.NumTypeParameters();
TypeArguments& type_args_obj = TypeArguments::Handle();
@@ -5293,7 +5122,7 @@
Type::New(cls, type_args_obj, Scanner::kNoSourcePos));
instantiated_type ^= ClassFinalizer::FinalizeType(
cls, instantiated_type, ClassFinalizer::kCanonicalize);
- return Api::NewHandle(I, instantiated_type.raw());
+ return Api::NewHandle(T, instantiated_type.raw());
}
@@ -5305,7 +5134,7 @@
}
const String& url = String::Handle(Z, lib.url());
ASSERT(!url.IsNull());
- return Api::NewHandle(I, url.raw());
+ return Api::NewHandle(T, url.raw());
}
@@ -5320,7 +5149,7 @@
return Api::NewError("%s: library '%s' not found.",
CURRENT_FUNC, url_str.ToCString());
} else {
- return Api::NewHandle(I, library.raw());
+ return Api::NewHandle(T, library.raw());
}
}
@@ -5328,6 +5157,7 @@
DART_EXPORT Dart_Handle Dart_LibraryHandleError(Dart_Handle library_in,
Dart_Handle error_in) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& lib = Api::UnwrapLibraryHandle(Z, library_in);
if (lib.IsNull()) {
@@ -5357,6 +5187,7 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const String& url_str = Api::UnwrapStringHandle(Z, url);
if (url_str.IsNull()) {
RETURN_TYPE_ERROR(Z, url, String);
@@ -5403,7 +5234,7 @@
// If this is the dart:_builtin library, register it with the VM.
if (url_str.Equals("dart:_builtin")) {
I->object_store()->set_builtin_library(library);
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(state)) {
return state;
}
@@ -5416,6 +5247,7 @@
Dart_Handle import,
Dart_Handle prefix) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& library_vm = Api::UnwrapLibraryHandle(Z, library);
if (library_vm.IsNull()) {
RETURN_TYPE_ERROR(Z, library, Library);
@@ -5460,6 +5292,7 @@
intptr_t line_offset,
intptr_t column_offset) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& lib = Api::UnwrapLibraryHandle(Z, library);
if (lib.IsNull()) {
RETURN_TYPE_ERROR(Z, library, Library);
@@ -5498,6 +5331,7 @@
Dart_Handle url,
Dart_Handle patch_source) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& lib = Api::UnwrapLibraryHandle(Z, library);
if (lib.IsNull()) {
RETURN_TYPE_ERROR(Z, library, Library);
@@ -5527,6 +5361,7 @@
// futures of loadLibrary calls (deferred library loading).
DART_EXPORT Dart_Handle Dart_FinalizeLoading(bool complete_futures) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
CHECK_CALLBACK_STATE(T);
I->DoneLoading();
@@ -5535,7 +5370,7 @@
// invoing of _completeDeferredLoads) into Isolate::DoneLoading().
// Finalize all classes if needed.
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(state)) {
return state;
}
@@ -5567,7 +5402,7 @@
Object::Handle(Z, DartEntry::InvokeFunction(function, args));
I->object_store()->clear_pending_deferred_loads();
if (res.IsError() || res.IsUnhandledException()) {
- return Api::NewHandle(I, res.raw());
+ return Api::NewHandle(T, res.raw());
}
}
return Api::Success();
@@ -5704,6 +5539,7 @@
const uint8_t* bytes,
intptr_t bytes_length) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (stream_id == NULL) {
RETURN_NULL_ERROR(stream_id);
}
@@ -5899,6 +5735,10 @@
DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
void* user_data) {
+ // To support various embedders, it must be possible to call this function
+ // from a thread for which we have not entered an Isolate and set up a Thread
+ // TLS object. Therefore, a Zone may not be available, a StackZone cannot be
+ // created, and no ZoneAllocated objects can be allocated.
if (consumer == NULL) {
return false;
}
@@ -5907,8 +5747,6 @@
// Nothing has been recorded.
return false;
}
- Thread* T = Thread::Current();
- StackZone zone(T);
Timeline::ReclaimCachedBlocksFromThreads();
JSONStream js;
TimelineEventFilter filter;
@@ -6031,7 +5869,7 @@
if (!FLAG_precompilation) {
return Dart_NewApiError("Flag --precompilation was not specified.");
}
- Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(result)) {
return result;
}
@@ -6039,7 +5877,7 @@
const Error& error = Error::Handle(Precompiler::CompileAll(entry_points,
reset_fields));
if (!error.IsNull()) {
- return Api::NewHandle(I, error.raw());
+ return Api::NewHandle(T, error.raw());
}
return Api::Success();
}
@@ -6054,6 +5892,7 @@
intptr_t* instructions_snapshot_size) {
ASSERT(FLAG_load_deferred_eagerly);
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (I->compilation_allowed()) {
return Dart_NewApiError("Isolate is not precompiled. "
"Did you forget to call Dart_Precompile?");
@@ -6077,7 +5916,7 @@
RETURN_NULL_ERROR(instructions_snapshot_size);
}
// Finalize all classes if needed.
- Dart_Handle state = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(state)) {
return state;
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 76b3aba..ccd8fa1 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -56,13 +56,12 @@
} while (0)
// Checks that the current isolate is not NULL and that it has an API scope.
-#define CHECK_ISOLATE_SCOPE(isolate) \
+#define CHECK_API_SCOPE(thread) \
do { \
- Isolate* tmp = (isolate); \
- CHECK_ISOLATE(tmp); \
- ApiState* state = tmp->api_state(); \
- ASSERT(state); \
- if (state->top_scope() == NULL) { \
+ Thread* tmpT = (thread); \
+ Isolate* tmpI = tmpT->isolate(); \
+ CHECK_ISOLATE(tmpI); \
+ if (tmpT->api_top_scope() == NULL) { \
FATAL1("%s expects to find a current scope. Did you forget to call " \
"Dart_EnterScope?", CURRENT_FUNC); \
} \
@@ -70,8 +69,7 @@
#define DARTSCOPE(thread) \
Thread* T = (thread); \
- Isolate* I = T->isolate(); \
- CHECK_ISOLATE_SCOPE(I); \
+ CHECK_API_SCOPE(T); \
HANDLESCOPE(T);
@@ -124,7 +122,7 @@
};
// Creates a new local handle.
- static Dart_Handle NewHandle(Isolate* isolate, RawObject* raw);
+ static Dart_Handle NewHandle(Thread* thread, RawObject* raw);
// Unwraps the raw object from the handle.
static RawObject* UnwrapHandle(Dart_Handle object);
@@ -146,7 +144,7 @@
// Returns an Error handle if isolate is in an inconsistent state
// or there was an error while finalizing classes.
// Returns a Success handle when no error condition exists.
- static Dart_Handle CheckAndFinalizePendingClasses(Isolate *isolate);
+ static Dart_Handle CheckAndFinalizePendingClasses(Thread *thread);
// Casts the internal Isolate* type to the external Dart_Isolate type.
static Dart_Isolate CastIsolate(Isolate* isolate);
@@ -216,7 +214,7 @@
}
// Retrieves the top ApiLocalScope.
- static ApiLocalScope* TopScope(Isolate* isolate);
+ static ApiLocalScope* TopScope(Thread* thread);
// Performs one-time initialization needed by the API.
static void InitOnce();
@@ -273,7 +271,7 @@
const String& name);
private:
- static Dart_Handle InitNewHandle(Isolate* isolate, RawObject* raw);
+ static Dart_Handle InitNewHandle(Thread* thread, RawObject* raw);
// Thread local key used by the API. Currently holds the current
// ApiNativeScope if any.
@@ -286,23 +284,6 @@
friend class ApiNativeScope;
};
-class IsolateSaver {
- public:
- explicit IsolateSaver(Isolate* current_isolate)
- : saved_isolate_(current_isolate) {
- }
- ~IsolateSaver() {
- // TODO(koda): Audit users; they should know whether they're in an isolate.
- if (saved_isolate_ != NULL) {
- Thread::EnterIsolate(saved_isolate_);
- }
- }
- private:
- Isolate* saved_isolate_;
-
- DISALLOW_COPY_AND_ASSIGN(IsolateSaver);
-};
-
// Start a scope in which no Dart API call backs are allowed.
#define START_NO_CALLBACK_SCOPE(thread) \
thread->IncrementNoCallbackScopeDepth()
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 3f5056f..1499f37 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -8,7 +8,7 @@
#include "include/dart_native_api.h"
#include "include/dart_tools_api.h"
#include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
#include "platform/utils.h"
#include "vm/class_finalizer.h"
#include "vm/dart_api_impl.h"
@@ -397,7 +397,6 @@
TEST_CASE(ErrorHandleTypes) {
- Isolate* isolate = Isolate::Current();
const String& compile_message = String::Handle(String::New("CompileError"));
const String& fatal_message = String::Handle(String::New("FatalError"));
@@ -406,9 +405,9 @@
Dart_Handle exception_error =
Dart_NewUnhandledExceptionError(NewString("ExceptionError"));
Dart_Handle compile_error =
- Api::NewHandle(isolate, LanguageError::New(compile_message));
+ Api::NewHandle(thread, LanguageError::New(compile_message));
Dart_Handle fatal_error =
- Api::NewHandle(isolate, UnwindError::New(fatal_message));
+ Api::NewHandle(thread, UnwindError::New(fatal_message));
EXPECT_VALID(not_error);
EXPECT(Dart_IsError(api_error));
@@ -450,13 +449,12 @@
TEST_CASE(UnhandleExceptionError) {
- Isolate* isolate = Isolate::Current();
const char* exception_cstr = "";
// Test with an API Error.
const char* kApiError = "Api Error Exception Test.";
Dart_Handle api_error = Api::NewHandle(
- isolate,
+ thread,
ApiError::New(String::Handle(String::New(kApiError))));
Dart_Handle exception_error = Dart_NewUnhandledExceptionError(api_error);
EXPECT(!Dart_IsApiError(exception_error));
@@ -471,7 +469,7 @@
const String& compile_message =
String::Handle(String::New(kCompileError));
Dart_Handle compile_error =
- Api::NewHandle(isolate, LanguageError::New(compile_message));
+ Api::NewHandle(thread, LanguageError::New(compile_message));
exception_error = Dart_NewUnhandledExceptionError(compile_error);
EXPECT(!Dart_IsApiError(exception_error));
EXPECT(Dart_IsUnhandledExceptionError(exception_error));
@@ -484,14 +482,14 @@
const String& fatal_message =
String::Handle(String::New("FatalError Exception Test."));
Dart_Handle fatal_error =
- Api::NewHandle(isolate, UnwindError::New(fatal_message));
+ Api::NewHandle(thread, UnwindError::New(fatal_message));
exception_error = Dart_NewUnhandledExceptionError(fatal_error);
EXPECT(Dart_IsError(exception_error));
EXPECT(!Dart_IsUnhandledExceptionError(exception_error));
// Test with a Regular object.
const char* kRegularString = "Regular String Exception Test.";
- Dart_Handle obj = Api::NewHandle(isolate, String::New(kRegularString));
+ Dart_Handle obj = Api::NewHandle(thread, String::New(kRegularString));
exception_error = Dart_NewUnhandledExceptionError(obj);
EXPECT(!Dart_IsApiError(exception_error));
EXPECT(Dart_IsUnhandledExceptionError(exception_error));
@@ -617,7 +615,7 @@
// Non-instance objects.
{
- DARTSCOPE(Thread::Current());
+ DARTSCOPE(thread);
Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
@@ -662,7 +660,7 @@
// Non-instance objects.
{
- DARTSCOPE(Thread::Current());
+ DARTSCOPE(thread);
Dart_Handle lib1 = Dart_LookupLibrary(dart_core);
Dart_Handle lib2 = Dart_LookupLibrary(dart_mirrors);
@@ -1226,7 +1224,7 @@
NULL);
EXPECT_VALID(small16);
{
- DARTSCOPE(Thread::Current());
+ DARTSCOPE(thread);
String& handle = String::Handle();
handle ^= Api::UnwrapHandle(big8);
EXPECT(handle.IsOld());
@@ -1260,7 +1258,7 @@
kSmallLength);
EXPECT_VALID(small);
{
- DARTSCOPE(Thread::Current());
+ DARTSCOPE(thread);
ExternalTypedData& handle = ExternalTypedData::Handle();
handle ^= Api::UnwrapHandle(big);
EXPECT(handle.IsOld());
@@ -2379,23 +2377,21 @@
UNIT_TEST_CASE(EnterExitScope) {
TestIsolateScope __test_isolate__;
- Isolate* isolate = Isolate::Current();
- EXPECT(isolate != NULL);
- ApiState* state = isolate->api_state();
- EXPECT(state != NULL);
- ApiLocalScope* scope = state->top_scope();
+ Thread* thread = Thread::Current();
+ EXPECT(thread != NULL);
+ ApiLocalScope* scope = thread->api_top_scope();
Dart_EnterScope();
{
- EXPECT(state->top_scope() != NULL);
+ EXPECT(thread->api_top_scope() != NULL);
DARTSCOPE(Thread::Current());
const String& str1 = String::Handle(String::New("Test String"));
- Dart_Handle ref = Api::NewHandle(isolate, str1.raw());
+ Dart_Handle ref = Api::NewHandle(thread, str1.raw());
String& str2 = String::Handle();
str2 ^= Api::UnwrapHandle(ref);
EXPECT(str1.Equals(str2));
}
Dart_ExitScope();
- EXPECT(scope == state->top_scope());
+ EXPECT(scope == thread->api_top_scope());
}
@@ -2409,17 +2405,17 @@
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
- ApiLocalScope* scope = state->top_scope();
+ ApiLocalScope* scope = thread->api_top_scope();
Dart_PersistentHandle handles[2000];
Dart_EnterScope();
{
DARTSCOPE(Thread::Current());
- Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
+ Dart_Handle ref1 = Api::NewHandle(thread, String::New(kTestString1));
for (int i = 0; i < 1000; i++) {
handles[i] = Dart_NewPersistentHandle(ref1);
}
Dart_EnterScope();
- Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
+ Dart_Handle ref2 = Api::NewHandle(thread, String::New(kTestString2));
for (int i = 1000; i < 2000; i++) {
handles[i] = Dart_NewPersistentHandle(ref2);
}
@@ -2460,7 +2456,7 @@
EXPECT(str.Equals(kTestString2));
}
}
- EXPECT(scope == state->top_scope());
+ EXPECT(scope == thread->api_top_scope());
EXPECT_EQ(2001, state->CountPersistentHandles());
Dart_ShutdownIsolate();
}
@@ -2502,22 +2498,22 @@
const char* kTestString2 = "Test String2";
TestIsolateScope __test_isolate__;
- Isolate* isolate = Isolate::Current();
+ DARTSCOPE(Thread::Current());
+ Isolate* isolate = T->isolate();
EXPECT(isolate != NULL);
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
- DARTSCOPE(Thread::Current());
String& str = String::Handle();
// Start with a known persistent handle.
- Dart_Handle ref1 = Api::NewHandle(isolate, String::New(kTestString1));
+ Dart_Handle ref1 = Api::NewHandle(T, String::New(kTestString1));
Dart_PersistentHandle obj = Dart_NewPersistentHandle(ref1);
EXPECT(state->IsValidPersistentHandle(obj));
str ^= PersistentHandle::Cast(obj)->raw();
EXPECT(str.Equals(kTestString1));
// Now create another local handle and assign it to the persistent handle.
- Dart_Handle ref2 = Api::NewHandle(isolate, String::New(kTestString2));
+ Dart_Handle ref2 = Api::NewHandle(T, String::New(kTestString2));
Dart_SetPersistentHandle(obj, ref2);
str ^= PersistentHandle::Cast(obj)->raw();
EXPECT(str.Equals(kTestString2));
@@ -2585,9 +2581,8 @@
// Create an object in old space.
Dart_Handle old_ref;
{
- Isolate* isolate = Isolate::Current();
DARTSCOPE(Thread::Current());
- old_ref = Api::NewHandle(isolate, String::New("old string", Heap::kOld));
+ old_ref = Api::NewHandle(thread, String::New("old string", Heap::kOld));
EXPECT_VALID(old_ref);
}
@@ -2753,7 +2748,6 @@
kWeak1ExternalSize,
NopCallback);
EXPECT_VALID(AsHandle(weak1));
- EXPECT(!Dart_IsPrologueWeakPersistentHandle(weak1));
Dart_ExitScope();
}
Dart_PersistentHandle strong_ref = NULL;
@@ -2788,33 +2782,6 @@
}
-TEST_CASE(PrologueWeakPersistentHandleExternalAllocationSize) {
- Heap* heap = Isolate::Current()->heap();
- EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
- EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
- Dart_WeakPersistentHandle pwph = NULL;
- static const intptr_t kWeakExternalSize = 1 * KB;
- {
- Dart_EnterScope();
- Dart_Handle obj = NewString("a string");
- EXPECT_VALID(obj);
- pwph = Dart_NewPrologueWeakPersistentHandle(
- obj, NULL, kWeakExternalSize, NopCallback);
- EXPECT_VALID(AsHandle(pwph));
- Dart_ExitScope();
- }
- EXPECT(heap->ExternalInWords(Heap::kNew) == kWeakExternalSize / kWordSize);
- EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
- // Promoting the string should transfer the external size to old.
- GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- EXPECT(heap->ExternalInWords(Heap::kNew) == 0);
- EXPECT(heap->ExternalInWords(Heap::kOld) == kWeakExternalSize / kWordSize);
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- EXPECT(heap->ExternalInWords(Heap::kOld) == 0);
-}
-
-
TEST_CASE(WeakPersistentHandleExternalAllocationSizeNewspaceGC) {
Dart_Isolate isolate = reinterpret_cast<Dart_Isolate>(Isolate::Current());
Heap* heap = Isolate::Current()->heap();
@@ -2860,14 +2827,14 @@
// Check that external allocation in old space can trigger GC.
Isolate* isolate = Isolate::Current();
Dart_EnterScope();
- Dart_Handle live = Api::NewHandle(isolate, String::New("live", Heap::kOld));
+ Dart_Handle live = Api::NewHandle(thread, String::New("live", Heap::kOld));
EXPECT_VALID(live);
Dart_WeakPersistentHandle weak = NULL;
EXPECT_EQ(0, isolate->heap()->ExternalInWords(Heap::kOld));
const intptr_t kSmallExternalSize = 1 * KB;
{
Dart_EnterScope();
- Dart_Handle dead = Api::NewHandle(isolate, String::New("dead", Heap::kOld));
+ Dart_Handle dead = Api::NewHandle(thread, String::New("dead", Heap::kOld));
EXPECT_VALID(dead);
weak = Dart_NewWeakPersistentHandle(dead,
NULL,
@@ -2927,402 +2894,6 @@
static Dart_WeakPersistentHandle weak1 = NULL;
static Dart_WeakPersistentHandle weak2 = NULL;
static Dart_WeakPersistentHandle weak3 = NULL;
-static Dart_WeakPersistentHandle weak4 = NULL;
-
-
-static void ObjectGroupsCallback(void* isolate_callback_data,
- Dart_WeakPersistentHandle handle,
- void* peer) {
- if (handle == weak1) {
- weak1 = NULL;
- } else if (handle == weak2) {
- weak2 = NULL;
- } else if (handle == weak3) {
- weak3 = NULL;
- } else if (handle == weak4) {
- weak4 = NULL;
- }
-}
-
-
-TEST_CASE(ObjectGroups) {
- Dart_PersistentHandle strong = NULL;
- Dart_WeakPersistentHandle strong_weak = NULL;
-
- Dart_EnterScope();
- {
- Isolate* isolate = Isolate::Current();
- DARTSCOPE(Thread::Current());
-
- Dart_Handle local = Api::NewHandle(
- isolate, String::New("strongly reachable", Heap::kOld));
- strong = Dart_NewPersistentHandle(local);
- strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
- EXPECT_VALID(AsHandle(strong));
- EXPECT(!Dart_IsNull(AsHandle(strong)));
-
- weak1 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
- NULL, 0, ObjectGroupsCallback);
- EXPECT_VALID(AsHandle(weak1));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
-
- weak2 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
- NULL, 0, ObjectGroupsCallback);
- EXPECT_VALID(AsHandle(weak2));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
-
- weak3 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
- NULL, 0, ObjectGroupsCallback);
- EXPECT_VALID(AsHandle(weak3));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
-
- weak4 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 4", Heap::kOld)),
- NULL, 0, ObjectGroupsCallback);
- EXPECT_VALID(AsHandle(weak4));
- EXPECT(!Dart_IsNull(AsHandle(weak4)));
- }
- Dart_ExitScope();
-
- {
- Dart_EnterScope();
- EXPECT_VALID(AsHandle(strong));
- EXPECT_VALID(AsHandle(weak1));
- EXPECT_VALID(AsHandle(weak2));
- EXPECT_VALID(AsHandle(weak3));
- EXPECT_VALID(AsHandle(weak4));
- Dart_ExitScope();
- }
-
- GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
- {
- Dart_EnterScope();
- // New space collection should not affect old space objects
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
- EXPECT(!Dart_IsNull(AsHandle(weak4)));
- Dart_ExitScope();
- }
-
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
- set = Dart_NewWeakReferenceSet(builder, weak3, weak3);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak2, weak2));
-
- set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
- EXPECT(!Dart_IsNull(AsHandle(weak4)));
- Dart_ExitScope();
- }
-
- {
- Dart_EnterScope();
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
-
- // Strong reference to weak3 to retain weak3 and weak4.
- Dart_PersistentHandle weak3_strong_ref =
- Dart_NewPersistentHandle(AsHandle(weak3));
- EXPECT_VALID(AsHandle(weak3_strong_ref));
-
- set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
-
- // Delete strong reference to weak3.
- Dart_DeletePersistentHandle(weak3_strong_ref);
- Dart_ExitScope();
- }
-
- {
- Dart_EnterScope();
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
- EXPECT(!Dart_IsNull(AsHandle(weak4)));
- Dart_ExitScope();
- }
-
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak1, weak1));
-
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
-
- set = Dart_NewWeakReferenceSet(builder, weak4, weak4);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak3));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // Only weak1 and weak2 should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(weak3 == NULL);
- EXPECT(weak4 == NULL);
- Dart_ExitScope();
- }
-
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakPersistentHandle lweak3 = Dart_NewWeakPersistentHandle(
- Dart_Null(), NULL, 0, NopCallback);
-
- Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, strong_weak, strong_weak));
-
- // lweak3 is unreferenced so weak2 is unreferenced and should be cleared
- set = Dart_NewWeakReferenceSet(builder, weak2, weak2);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak3, lweak3));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // Only weak1 should be preserved, weak3 should not preserve weak2.
- EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(weak2 == NULL);
- EXPECT(weak3 == NULL); // was cleared, should remain cleared
- EXPECT(weak4 == NULL); // was cleared, should remain cleared
- Dart_ExitScope();
- }
-
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakPersistentHandle lweak2 = Dart_NewWeakPersistentHandle(
- Dart_Null(), NULL, 0, NopCallback);
- Dart_WeakPersistentHandle lweak3 = Dart_NewWeakPersistentHandle(
- Dart_Null(), NULL, 0, NopCallback);
- Dart_WeakPersistentHandle lweak4 = Dart_NewWeakPersistentHandle(
- Dart_Null(), NULL, 0, NopCallback);
- // lweak{2,3,4} are cleared and should have no effect on weak1
- Dart_WeakReferenceSet set =
- Dart_NewWeakReferenceSet(builder, strong_weak, strong_weak);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak2, lweak2));
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak3, lweak3));
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, lweak4, lweak4));
-
- // weak1 is weakly reachable and should be cleared
- set = Dart_NewWeakReferenceSet(builder, weak1, weak1);
- EXPECT_NOTNULL(set);
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // All weak references should now be cleared.
- EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
- EXPECT(weak1 == NULL);
- EXPECT(weak2 == NULL);
- EXPECT(weak3 == NULL);
- EXPECT(weak4 == NULL);
- Dart_ExitScope();
- }
-}
-
-
-TEST_CASE(DuplicateWeakReferenceSetEntries) {
- Isolate* isolate = Isolate::Current();
- Dart_PersistentHandle strong = NULL;
- Dart_WeakPersistentHandle weak = NULL; // A weak handle to strong.
-
- Dart_EnterScope();
- {
- DARTSCOPE(Thread::Current());
-
- // Strong handle to keep the reference set alive.
- Dart_Handle local = Api::NewHandle(isolate, String::New("string"));
- strong = Dart_NewPersistentHandle(local);
- EXPECT_VALID(AsHandle(strong));
- EXPECT(!Dart_IsNull(AsHandle(strong)));
- // Corresponding weak handle to use as key and duplicated value.
- weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
- EXPECT_VALID(AsHandle(weak));
- EXPECT(!Dart_IsNull(AsHandle(weak)));
- }
- Dart_ExitScope();
-
- {
- Dart_EnterScope();
- // Create the weak reference set.
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
- // Register the key and the first copy of the value.
- Dart_WeakReferenceSet set = Dart_NewWeakReferenceSet(builder, weak, weak);
- EXPECT_NOTNULL(set);
- // Add the second copy of the value.
- Dart_Handle result = Dart_AppendValueToWeakReferenceSet(set, weak);
- EXPECT_VALID(result);
-
- // Trigger GC to ensure that we can visit duplicate entries in weak
- // reference sets.
- isolate->heap()->CollectGarbage(Heap::kNew);
- Dart_ExitScope();
- }
-}
-
-
-static Dart_WeakPersistentHandle old_pwph = NULL;
-static Dart_WeakPersistentHandle new_pwph = NULL;
-
-
-static void PrologueWeakHandleCallback(void* isolate_callback_data,
- Dart_WeakPersistentHandle handle,
- void* peer) {
- if (handle == old_pwph) {
- old_pwph = NULL;
- } else if (handle == new_pwph) {
- new_pwph = NULL;
- }
-}
-
-
-TEST_CASE(PrologueWeakPersistentHandles) {
- Dart_EnterScope();
- {
- Isolate* isolate = Isolate::Current();
- DARTSCOPE(Thread::Current());
- new_pwph = Dart_NewPrologueWeakPersistentHandle(
- Api::NewHandle(isolate,
- String::New("new space prologue weak", Heap::kNew)),
- NULL, 0, PrologueWeakHandleCallback);
- EXPECT_VALID(AsHandle(new_pwph));
- EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
- old_pwph = Dart_NewPrologueWeakPersistentHandle(
- Api::NewHandle(isolate,
- String::New("old space prologue weak", Heap::kOld)),
- NULL, 0, PrologueWeakHandleCallback);
- EXPECT_VALID(AsHandle(old_pwph));
- EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
- }
- Dart_ExitScope();
-
- {
- Dart_EnterScope();
- EXPECT_VALID(AsHandle(new_pwph));
- EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
- EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
- EXPECT_VALID(AsHandle(old_pwph));
- EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
- EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
- Dart_ExitScope();
- }
-
- // Garbage collect new space without invoking API callbacks.
- GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
- {
- Dart_EnterScope();
- // Both prologue weak handles should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
- EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
- Dart_ExitScope();
- }
-
- // Garbage collect old space without invoking API callbacks.
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
- Heap::kIgnoreApiCallbacks,
- Heap::kGCTestCase);
-
- {
- Dart_EnterScope();
- // Both prologue weak handles should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
- EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
- Dart_ExitScope();
- }
-
- // Garbage collect new space invoking API callbacks.
- GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
-
- {
- Dart_EnterScope();
- // The prologue weak handle with a new space referent should now be
- // cleared. The old space referent should be preserved.
- EXPECT(new_pwph == NULL);
- EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
- Dart_ExitScope();
- }
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
- Heap::kInvokeApiCallbacks,
- Heap::kGCTestCase);
-
- {
- Dart_EnterScope();
- // The prologue weak handle with an old space referent should now be
- // cleared. The new space referent should remain cleared.
- EXPECT(new_pwph == NULL);
- EXPECT(old_pwph == NULL);
- Dart_ExitScope();
- }
-}
static void ImplicitReferencesCallback(void* isolate_callback_data,
@@ -3344,11 +2915,10 @@
Dart_EnterScope();
{
- Isolate* isolate = Isolate::Current();
DARTSCOPE(Thread::Current());
Dart_Handle local = Api::NewHandle(
- isolate, String::New("strongly reachable", Heap::kOld));
+ thread, String::New("strongly reachable", Heap::kOld));
strong = Dart_NewPersistentHandle(local);
strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
@@ -3359,19 +2929,19 @@
EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
weak1 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
+ Api::NewHandle(thread, String::New("weakly reachable 1", Heap::kOld)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak1)));
EXPECT_VALID(AsHandle(weak1));
weak2 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
+ Api::NewHandle(thread, String::New("weakly reachable 2", Heap::kOld)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak2)));
EXPECT_VALID(AsHandle(weak2));
weak3 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
+ Api::NewHandle(thread, String::New("weakly reachable 3", Heap::kOld)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak3)));
EXPECT_VALID(AsHandle(weak3));
@@ -3398,53 +2968,6 @@
EXPECT(!Dart_IsNull(AsHandle(weak3)));
Dart_ExitScope();
}
-
- // A strongly referenced key should preserve all the values.
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set =
- Dart_NewWeakReferenceSet(builder, strong_weak, 0);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak1));
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak2));
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak3));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // All weak references should be preserved.
- EXPECT_VALID(AsHandle(strong_weak));
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
- Dart_ExitScope();
- }
-
- // Key membership does not imply a strong reference.
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set =
- Dart_NewWeakReferenceSet(builder, strong_weak, weak1);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendToWeakReferenceSet(set, weak3, weak2));
-
- Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- }
-
- {
- Dart_EnterScope();
- // All weak references except weak3 should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(weak3 == NULL);
- Dart_ExitScope();
- }
}
@@ -3455,11 +2978,10 @@
Dart_EnterScope();
{
- Isolate* isolate = Isolate::Current();
DARTSCOPE(Thread::Current());
Dart_Handle local = Api::NewHandle(
- isolate, String::New("strongly reachable", Heap::kOld));
+ thread, String::New("strongly reachable", Heap::kOld));
strong = Dart_NewPersistentHandle(local);
strong_weak = Dart_NewWeakPersistentHandle(local, NULL, 0, NopCallback);
@@ -3470,19 +2992,19 @@
EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
weak1 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kNew)),
+ Api::NewHandle(thread, String::New("weakly reachable 1", Heap::kNew)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak1)));
EXPECT_VALID(AsHandle(weak1));
weak2 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kNew)),
+ Api::NewHandle(thread, String::New("weakly reachable 2", Heap::kNew)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak2)));
EXPECT_VALID(AsHandle(weak2));
weak3 = Dart_NewWeakPersistentHandle(
- Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kNew)),
+ Api::NewHandle(thread, String::New("weakly reachable 3", Heap::kNew)),
NULL, 0, ImplicitReferencesCallback);
EXPECT(!Dart_IsNull(AsHandle(weak3)));
EXPECT_VALID(AsHandle(weak3));
@@ -3508,41 +3030,6 @@
EXPECT(!Dart_IsNull(AsHandle(weak3)));
Dart_ExitScope();
}
-
- // A strongly referenced key should preserve all the values.
- {
- Dart_WeakReferenceSetBuilder builder = Dart_NewWeakReferenceSetBuilder();
- EXPECT_NOTNULL(builder);
-
- Dart_WeakReferenceSet set =
- Dart_NewWeakReferenceSet(builder, strong_weak, 0);
- EXPECT_NOTNULL(set);
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak1));
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak2));
- EXPECT_VALID(Dart_AppendValueToWeakReferenceSet(set, weak3));
-
- GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
- }
-
- {
- Dart_EnterScope();
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(AsHandle(weak1)));
- EXPECT(!Dart_IsNull(AsHandle(weak2)));
- EXPECT(!Dart_IsNull(AsHandle(weak3)));
- Dart_ExitScope();
- }
-
- GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
-
- {
- Dart_EnterScope();
- // No weak references should be preserved.
- EXPECT(weak1 == NULL);
- EXPECT(weak2 == NULL);
- EXPECT(weak3 == NULL);
- Dart_ExitScope();
- }
}
@@ -3715,9 +3202,7 @@
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
EXPECT(isolate != NULL);
- ApiState* state = isolate->api_state();
- EXPECT(state != NULL);
- ApiLocalScope* scope = state->top_scope();
+ ApiLocalScope* scope = thread->api_top_scope();
Dart_Handle handles[300];
{
StackZone zone(thread);
@@ -3727,9 +3212,9 @@
// Start a new scope and allocate some local handles.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
- handles[i] = Api::NewHandle(isolate, Smi::New(i));
+ handles[i] = Api::NewHandle(thread, Smi::New(i));
}
- EXPECT_EQ(100, state->CountLocalHandles());
+ EXPECT_EQ(100, thread->CountLocalHandles());
for (int i = 0; i < 100; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
@@ -3738,9 +3223,9 @@
{
Dart_EnterScope();
for (int i = 100; i < 200; i++) {
- handles[i] = Api::NewHandle(isolate, Smi::New(i));
+ handles[i] = Api::NewHandle(thread, Smi::New(i));
}
- EXPECT_EQ(200, state->CountLocalHandles());
+ EXPECT_EQ(200, thread->CountLocalHandles());
for (int i = 100; i < 200; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
@@ -3750,25 +3235,25 @@
{
Dart_EnterScope();
for (int i = 200; i < 300; i++) {
- handles[i] = Api::NewHandle(isolate, Smi::New(i));
+ handles[i] = Api::NewHandle(thread, Smi::New(i));
}
- EXPECT_EQ(300, state->CountLocalHandles());
+ EXPECT_EQ(300, thread->CountLocalHandles());
for (int i = 200; i < 300; i++) {
val ^= Api::UnwrapHandle(handles[i]);
EXPECT_EQ(i, val.Value());
}
- EXPECT_EQ(300, state->CountLocalHandles());
+ EXPECT_EQ(300, thread->CountLocalHandles());
VERIFY_ON_TRANSITION;
Dart_ExitScope();
}
- EXPECT_EQ(200, state->CountLocalHandles());
+ EXPECT_EQ(200, thread->CountLocalHandles());
Dart_ExitScope();
}
- EXPECT_EQ(100, state->CountLocalHandles());
+ EXPECT_EQ(100, thread->CountLocalHandles());
Dart_ExitScope();
}
- EXPECT_EQ(0, state->CountLocalHandles());
- EXPECT(scope == state->top_scope());
+ EXPECT_EQ(0, thread->CountLocalHandles());
+ EXPECT(scope == thread->api_top_scope());
Dart_ShutdownIsolate();
}
@@ -3778,25 +3263,23 @@
// exits.
UNIT_TEST_CASE(LocalZoneMemory) {
TestCase::CreateTestIsolate();
- Isolate* isolate = Isolate::Current();
- EXPECT(isolate != NULL);
- ApiState* state = isolate->api_state();
- EXPECT(state != NULL);
- ApiLocalScope* scope = state->top_scope();
+ Thread* thread = Thread::Current();
+ EXPECT(thread != NULL);
+ ApiLocalScope* scope = thread->api_top_scope();
{
// Start a new scope and allocate some memory.
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Dart_ScopeAllocate(16);
}
- EXPECT_EQ(1600, state->ZoneSizeInBytes());
+ EXPECT_EQ(1600, thread->ZoneSizeInBytes());
// Start another scope and allocate some more memory.
{
Dart_EnterScope();
for (int i = 0; i < 100; i++) {
Dart_ScopeAllocate(16);
}
- EXPECT_EQ(3200, state->ZoneSizeInBytes());
+ EXPECT_EQ(3200, thread->ZoneSizeInBytes());
{
// Start another scope and allocate some more memory.
{
@@ -3804,18 +3287,18 @@
for (int i = 0; i < 200; i++) {
Dart_ScopeAllocate(16);
}
- EXPECT_EQ(6400, state->ZoneSizeInBytes());
+ EXPECT_EQ(6400, thread->ZoneSizeInBytes());
Dart_ExitScope();
}
}
- EXPECT_EQ(3200, state->ZoneSizeInBytes());
+ EXPECT_EQ(3200, thread->ZoneSizeInBytes());
Dart_ExitScope();
}
- EXPECT_EQ(1600, state->ZoneSizeInBytes());
+ EXPECT_EQ(1600, thread->ZoneSizeInBytes());
Dart_ExitScope();
}
- EXPECT_EQ(0, state->ZoneSizeInBytes());
- EXPECT(scope == state->top_scope());
+ EXPECT_EQ(0, thread->ZoneSizeInBytes());
+ EXPECT(scope == thread->api_top_scope());
Dart_ShutdownIsolate();
}
@@ -5344,7 +4827,7 @@
Thread* thread = Thread::Current();
const Library& library_obj = Api::UnwrapLibraryHandle(thread->zone(), lib);
const String& name = String::Handle(String::New(str));
- return Api::NewHandle(thread->isolate(), library_obj.PrivateName(name));
+ return Api::NewHandle(thread, library_obj.PrivateName(name));
}
@@ -5755,11 +5238,7 @@
const char* kScriptChars =
"int test() native \"ThrowException_native\";";
Dart_Handle result;
- Isolate* isolate = Isolate::Current();
- EXPECT(isolate != NULL);
- ApiState* state = isolate->api_state();
- EXPECT(state != NULL);
- intptr_t size = state->ZoneSizeInBytes();
+ intptr_t size = thread->ZoneSizeInBytes();
Dart_EnterScope(); // Start a Dart API scope for invoking API functions.
// Load up a test script which extends the native wrapper class.
@@ -5778,7 +5257,7 @@
EXPECT(Dart_ErrorHasException(result));
Dart_ExitScope(); // Exit the Dart API scope.
- EXPECT_EQ(size, state->ZoneSizeInBytes());
+ EXPECT_EQ(size, thread->ZoneSizeInBytes());
}
@@ -7598,24 +7077,15 @@
const char* kScriptChars =
"import 'builtin';\n"
"import 'dart:isolate';\n"
- "void entry(message) {\n"
- " var data = message[0];\n"
- " var replyTo = message[1];\n"
- " if (data) {\n"
- " throw new Exception('MakeChildExit');\n"
- " } else {\n"
- " replyTo.send('hello');\n"
- " }\n"
- "}\n"
- "\n"
- "void main(exc_child, exc_parent) {\n"
- " var receivePort = new RawReceivePort();\n"
- " Isolate.spawn(entry, [exc_child, receivePort.sendPort]);\n"
- " receivePort.handler = (message) {\n"
- " receivePort.close();\n"
- " if (message != 'hello') throw new Exception('ShouldNotHappen');\n"
- " if (exc_parent) throw new Exception('MakeParentExit');\n"
+ "void main(shouldThrowException) {\n"
+ " var rp = new RawReceivePort();\n"
+ " rp.handler = (msg) {\n"
+ " rp.close();\n"
+ " if (shouldThrowException) {\n"
+ " throw new Exception('ExceptionFromTimer');\n"
+ " }\n"
" };\n"
+ " rp.sendPort.send(1);\n"
"}\n";
if (Dart_CurrentIsolate() != NULL) {
@@ -7643,28 +7113,10 @@
}
-// The error string from the last unhandled exception. This value is only
-// valid until the next Dart_ExitScope().
-static char* last_exception = NULL;
-
-
-static void RunLoopUnhandledExceptionCallback(Dart_Handle exception) {
- Dart_Handle error_string = Dart_ToString(exception);
- EXPECT_VALID(error_string);
- const char* error_text;
- Dart_Handle result = Dart_StringToCString(error_string, &error_text);
- // Duplicate the string since error text is freed when callback is finished.
- last_exception = strdup(error_text);
- EXPECT_VALID(result);
-}
-
-
// Common code for RunLoop_Success/RunLoop_Failure.
-static void RunLoopTest(bool throw_exception_child,
- bool throw_exception_parent) {
+static void RunLoopTest(bool throw_exception) {
Dart_IsolateCreateCallback saved = Isolate::CreateCallback();
Isolate::SetCreateCallback(RunLoopTestCallback);
- Isolate::SetUnhandledExceptionCallback(RunLoopUnhandledExceptionCallback);
Dart_Isolate isolate = RunLoopTestCallback(
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
@@ -7674,29 +7126,15 @@
EXPECT_VALID(lib);
Dart_Handle result;
- Dart_Handle args[2];
- args[0] = (throw_exception_child ? Dart_True() : Dart_False());
- args[1] = (throw_exception_parent ? Dart_True() : Dart_False());
- result = Dart_Invoke(lib, NewString("main"), 2, args);
+ Dart_Handle args[1];
+ args[0] = (throw_exception ? Dart_True() : Dart_False());
+ result = Dart_Invoke(lib, NewString("main"), 1, args);
EXPECT_VALID(result);
- if (throw_exception_child) {
- // TODO(tball): fix race-condition
- // EXPECT_NOTNULL(last_exception);
- // EXPECT_STREQ("UnhandledException", last_exception);
+ result = Dart_RunLoop();
+ if (throw_exception) {
+ EXPECT_ERROR(result, "Exception: ExceptionFromTimer");
} else {
- result = Dart_RunLoop();
- if (throw_exception_parent) {
- EXPECT_ERROR(result, "Exception: MakeParentExit");
- EXPECT_NOTNULL(last_exception);
- EXPECT_STREQ("UnhandledException", last_exception);
- } else {
- EXPECT_VALID(result);
- EXPECT(last_exception == NULL);
- }
- }
- if (last_exception != NULL) {
- free(last_exception);
- last_exception = NULL;
+ EXPECT_VALID(result);
}
Dart_ExitScope();
@@ -7707,18 +7145,12 @@
UNIT_TEST_CASE(RunLoop_Success) {
- RunLoopTest(false, false);
+ RunLoopTest(false);
}
-// This test exits the vm. Listed as FAIL in vm.status.
-UNIT_TEST_CASE(RunLoop_ExceptionChild) {
- RunLoopTest(true, false);
-}
-
-
-UNIT_TEST_CASE(RunLoop_ExceptionParent) {
- RunLoopTest(false, true);
+UNIT_TEST_CASE(RunLoop_Exception) {
+ RunLoopTest(true);
}
@@ -7805,81 +7237,6 @@
}
-// This callback handles isolate interrupts for the IsolateInterrupt
-// test. It ignores the first two interrupts and throws an exception
-// on the third interrupt.
-const int kInterruptCount = 10;
-static int interrupt_count = 0;
-static bool IsolateInterruptTestCallback() {
- OS::Print(" ========== Interrupt callback called #%d\n", interrupt_count + 1);
- {
- MonitorLocker ml(sync);
- interrupt_count++;
- ml.Notify();
- }
- if (interrupt_count == kInterruptCount) {
- Dart_EnterScope();
- Dart_Handle lib = Dart_LookupLibrary(NewString(TestCase::url()));
- EXPECT_VALID(lib);
- Dart_Handle exc = NewString("foo");
- EXPECT_VALID(exc);
- Dart_Handle result = Dart_ThrowException(exc);
- EXPECT_VALID(result);
- UNREACHABLE(); // Dart_ThrowException only returns if it gets an error.
- return false;
- }
- ASSERT(interrupt_count < kInterruptCount);
- return true;
-}
-
-
-TEST_CASE(IsolateInterrupt) {
- Dart_IsolateInterruptCallback saved = Isolate::InterruptCallback();
- Isolate::SetInterruptCallback(IsolateInterruptTestCallback);
-
- sync = new Monitor();
- int result = OSThread::Start(BusyLoop_start, 0);
- EXPECT_EQ(0, result);
-
- {
- MonitorLocker ml(sync);
- // Wait for the other isolate to enter main.
- while (!main_entered) {
- ml.Wait();
- }
- }
-
- // Send a number of interrupts to the other isolate. All but the
- // last allow execution to continue. The last causes an exception in
- // the isolate.
- for (int i = 0; i < kInterruptCount; i++) {
- // Space out the interrupts a bit.
- OS::Sleep(i + 1);
- Dart_InterruptIsolate(shared_isolate);
- {
- MonitorLocker ml(sync);
- // Wait for interrupt_count to be increased.
- while (interrupt_count == i) {
- ml.Wait();
- }
- OS::Print(" ========== Interrupt processed #%d\n", interrupt_count);
- }
- }
-
- {
- MonitorLocker ml(sync);
- // Wait for our isolate to finish.
- while (shared_isolate != NULL) {
- ml.Wait();
- }
- }
-
- // We should have received the expected number of interrupts.
- EXPECT_EQ(kInterruptCount, interrupt_count);
-
- Isolate::SetInterruptCallback(saved);
-}
-
static void* saved_callback_data;
static void IsolateShutdownTestCallback(void* callback_data) {
saved_callback_data = callback_data;
@@ -8600,7 +7957,7 @@
// by one.
TEST_CASE(OneOldSpacePeer) {
Isolate* isolate = Isolate::Current();
- Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
+ Dart_Handle str = Api::NewHandle(thread, String::New("str", Heap::kOld));
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8633,7 +7990,7 @@
Dart_EnterScope();
{
DARTSCOPE(Thread::Current());
- Dart_Handle str = Api::NewHandle(isolate, String::New("str", Heap::kOld));
+ Dart_Handle str = Api::NewHandle(T, String::New("str", Heap::kOld));
EXPECT_VALID(str);
EXPECT(Dart_IsString(str));
EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8662,7 +8019,7 @@
// by two.
TEST_CASE(TwoOldSpacePeers) {
Isolate* isolate = Isolate::Current();
- Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
+ Dart_Handle s1 = Api::NewHandle(thread, String::New("s1", Heap::kOld));
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8675,7 +8032,7 @@
o1 = &o1;
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
- Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
+ Dart_Handle s2 = Api::NewHandle(thread, String::New("s2", Heap::kOld));
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
@@ -8709,7 +8066,7 @@
Dart_EnterScope();
{
DARTSCOPE(Thread::Current());
- Dart_Handle s1 = Api::NewHandle(isolate, String::New("s1", Heap::kOld));
+ Dart_Handle s1 = Api::NewHandle(T, String::New("s1", Heap::kOld));
EXPECT_VALID(s1);
EXPECT(Dart_IsString(s1));
EXPECT_EQ(0, isolate->heap()->PeerCount());
@@ -8722,7 +8079,7 @@
o1 = &o1;
EXPECT_VALID(Dart_GetPeer(s1, &o1));
EXPECT(o1 == reinterpret_cast<void*>(&p1));
- Dart_Handle s2 = Api::NewHandle(isolate, String::New("s2", Heap::kOld));
+ Dart_Handle s2 = Api::NewHandle(T, String::New("s2", Heap::kOld));
EXPECT_VALID(s2);
EXPECT(Dart_IsString(s2));
EXPECT_EQ(1, isolate->heap()->PeerCount());
@@ -8815,8 +8172,7 @@
// Test with single character canonical string, it should not become
// external string but the peer should be setup for it.
- Isolate* isolate = Isolate::Current();
- Dart_Handle canonical_str = Api::NewHandle(isolate, Symbols::New("*"));
+ Dart_Handle canonical_str = Api::NewHandle(thread, Symbols::New("*"));
EXPECT(Dart_IsString(canonical_str));
EXPECT(!Dart_IsExternalString(canonical_str));
uint8_t ext_canonical_str[kLength];
@@ -8907,7 +8263,7 @@
const char* symbol_ascii = "?unseen";
expected_length = strlen(symbol_ascii);
Dart_Handle symbol_str =
- Api::NewHandle(isolate, Symbols::New(symbol_ascii, expected_length));
+ Api::NewHandle(thread, Symbols::New(symbol_ascii, expected_length));
EXPECT_VALID(symbol_str);
EXPECT(Dart_IsString(symbol_str));
EXPECT(Dart_IsStringLatin1(symbol_str));
@@ -9782,8 +9138,14 @@
// Grab the global trace.
AppendData data;
- success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
- EXPECT(success);
+ {
+ Thread* T = Thread::Current();
+ StackZone zone(T);
+ success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
+ EXPECT(success);
+ // The call should do no zone allocation.
+ EXPECT(zone.SizeInBytes() == 0);
+ }
buffer = reinterpret_cast<char*>(data.buffer);
buffer_length = data.buffer_length;
EXPECT(buffer_length > 0);
@@ -9823,8 +9185,13 @@
}
// Grab the global trace.
- success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
- EXPECT(success);
+ {
+ Thread* T = Thread::Current();
+ StackZone zone(T);
+ success = Dart_GlobalTimelineGetTrace(AppendStreamConsumer, &data);
+ EXPECT(success);
+ EXPECT(zone.SizeInBytes() == 0);
+ }
buffer = reinterpret_cast<char*>(data.buffer);
buffer_length = data.buffer_length;
EXPECT(buffer_length > 0);
@@ -9849,4 +9216,165 @@
free(data.buffer);
}
+
+class GlobalTimelineThreadData {
+ public:
+ GlobalTimelineThreadData()
+ : monitor_(new Monitor()),
+ data_(new AppendData()),
+ running_(true),
+ join_id_(OSThread::kInvalidThreadJoinId) {
+ }
+
+ ~GlobalTimelineThreadData() {
+ delete monitor_;
+ monitor_ = NULL;
+ free(data_->buffer);
+ data_->buffer = NULL;
+ data_->buffer_length = 0;
+ delete data_;
+ data_ = NULL;
+ }
+
+ Monitor* monitor() const { return monitor_; }
+ bool running() const { return running_; }
+ AppendData* data() const { return data_; }
+ uint8_t* buffer() const { return data_->buffer; }
+ intptr_t buffer_length() const { return data_->buffer_length; }
+ ThreadJoinId join_id() const { return join_id_; }
+
+ void set_running(bool running) { running_ = running; }
+ void set_join_id(ThreadJoinId join_id) { join_id_ = join_id; }
+
+ private:
+ Monitor* monitor_;
+ AppendData* data_;
+ bool running_;
+ ThreadJoinId join_id_;
+};
+
+
+static void GlobalTimelineThread(uword parameter) {
+ GlobalTimelineThreadData* data =
+ reinterpret_cast<GlobalTimelineThreadData*>(parameter);
+ Thread* T = Thread::Current();
+ // When there is no current Thread, then Zone allocation will fail.
+ EXPECT(T == NULL);
+ {
+ MonitorLocker ml(data->monitor());
+ bool success =
+ Dart_GlobalTimelineGetTrace(AppendStreamConsumer, data->data());
+ EXPECT(success);
+ data->set_running(false);
+ data->set_join_id(OSThread::Current()->join_id());
+ ml.Notify();
+ }
+}
+
+
+// This test is the same as the one above except that the calls to
+// Dart_GlobalTimelineGetTrace are made from a fresh thread. This ensures that
+// we can call the function from a thread for which we have not set up a
+// Thread object.
+TEST_CASE(Timeline_Dart_GlobalTimelineGetTrace_Threaded) {
+ const char* kScriptChars =
+ "bar() => 'z';\n"
+ "foo() => 'a';\n"
+ "main() => foo();\n";
+
+ // Enable all streams.
+ Dart_GlobalTimelineSetRecordedStreams(DART_TIMELINE_STREAM_ALL |
+ DART_TIMELINE_STREAM_VM);
+ Dart_Handle lib;
+ {
+ // Add something to the VM stream.
+ TimelineDurationScope tds(Timeline::GetVMStream(),
+ "TestVMDuration");
+ lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ }
+
+ // Invoke main, which will be compiled resulting in a compiler event in
+ // the timeline.
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ const char* buffer = NULL;
+ intptr_t buffer_length = 0;
+
+ // Run Dart_GlobalTimelineGetTrace on a fresh thread.
+ GlobalTimelineThreadData data;
+ int err = OSThread::Start("Timeline test thread",
+ GlobalTimelineThread, reinterpret_cast<uword>(&data));
+ EXPECT(err == 0);
+ {
+ MonitorLocker ml(data.monitor());
+ while (data.running()) {
+ ml.Wait();
+ }
+ buffer = reinterpret_cast<char*>(data.buffer());
+ buffer_length = data.buffer_length();
+ OSThread::Join(data.join_id());
+ }
+ EXPECT(buffer_length > 0);
+ EXPECT(buffer != NULL);
+
+ // Response starts with a '{' character and not a '['.
+ EXPECT(buffer[0] == '{');
+ // Response ends with a '}' character and not a ']'.
+ EXPECT(buffer[buffer_length - 1] == '\0');
+ EXPECT(buffer[buffer_length - 2] == '}');
+
+ // Heartbeat test.
+ EXPECT_SUBSTRING("\"name\":\"TestVMDuration\"", buffer);
+ EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+ EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+ EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+ EXPECT_NOTSUBSTRING("\"function\":\"::_bar\"", buffer);
+
+ // Retrieving the global trace resulted in all open blocks being reclaimed.
+ // Add some new events and verify that both sets of events are present
+ // in the resulting trace.
+ {
+ // Add something to the VM stream.
+ TimelineDurationScope tds(Timeline::GetVMStream(),
+ "TestVMDuration2");
+ // Invoke bar, which will be compiled resulting in a compiler event in
+ // the timeline.
+ result = Dart_Invoke(lib, NewString("bar"), 0, NULL);
+ }
+
+ // Grab the global trace.
+ GlobalTimelineThreadData data2;
+ err = OSThread::Start("Timeline test thread",
+ GlobalTimelineThread, reinterpret_cast<uword>(&data2));
+ EXPECT(err == 0);
+ {
+ MonitorLocker ml(data2.monitor());
+ while (data2.running()) {
+ ml.Wait();
+ }
+ buffer = reinterpret_cast<char*>(data2.buffer());
+ buffer_length = data2.buffer_length();
+ OSThread::Join(data2.join_id());
+ }
+
+ EXPECT(buffer_length > 0);
+ EXPECT(buffer != NULL);
+ // Response starts with a '{' character and not a '['.
+ EXPECT(buffer[0] == '{');
+ // Response ends with a '}' character and not a ']'.
+ EXPECT(buffer[buffer_length - 1] == '\0');
+ EXPECT(buffer[buffer_length - 2] == '}');
+
+ // Heartbeat test for old events.
+ EXPECT_SUBSTRING("\"name\":\"TestVMDuration\"", buffer);
+ EXPECT_SUBSTRING("\"cat\":\"Compiler\"", buffer);
+ EXPECT_SUBSTRING("\"name\":\"CompileFunction\"", buffer);
+ EXPECT_SUBSTRING("\"function\":\"::_main\"", buffer);
+
+ // Heartbeat test for new events.
+ EXPECT_SUBSTRING("\"name\":\"TestVMDuration2\"", buffer);
+ EXPECT_SUBSTRING("\"function\":\"::_bar\"", buffer);
+}
+
} // namespace dart
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index 207aab4..e0f6e00 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -203,7 +203,6 @@
public:
static FinalizablePersistentHandle* New(
Isolate* isolate,
- bool is_prologue,
const Object& object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback,
@@ -251,22 +250,13 @@
set_external_size(0);
}
- bool IsPrologueWeakPersistent() {
- return PrologueWeakBit::decode(external_data_);
- }
-
- void SetPrologueWeakPersistent(bool value) {
- external_data_ = PrologueWeakBit::update(value, external_data_);
- }
-
static FinalizablePersistentHandle* Cast(Dart_WeakPersistentHandle handle);
private:
enum {
kExternalNewSpaceBit = 0,
- kPrologueWeakBit = 1,
- kExternalSizeBits = 2,
- kExternalSizeBitsSize = (kBitsPerWord - 2),
+ kExternalSizeBits = 1,
+ kExternalSizeBitsSize = (kBitsPerWord - 1),
};
// This part of external_data_ is the number of externally allocated bytes.
@@ -277,8 +267,6 @@
// This bit of external_data_ is true if the referent was created in new
// space and UpdateRelocated has not yet detected any promotion.
class ExternalNewSpaceBit : public BitField<bool, kExternalNewSpaceBit, 1> {};
- // This bit is used to indicate that it is a prologue weak persistent handle.
- class PrologueWeakBit : public BitField<bool, kPrologueWeakBit, 1> {};
friend class FinalizablePersistentHandles;
@@ -673,11 +661,6 @@
};
-// Forward declarations.
-class WeakReferenceSetBuilder;
-class WeakReferenceSet;
-
-
// Implementation of the API State used in dart api for maintaining
// local scopes, persistent handles etc. These are setup on a per isolate
// basis and destroyed when the isolate is shutdown.
@@ -685,20 +668,11 @@
public:
ApiState() : persistent_handles_(),
weak_persistent_handles_(),
- prologue_weak_persistent_handles_(),
- reusable_scope_(NULL),
- top_scope_(NULL),
- delayed_weak_reference_sets_(NULL),
null_(NULL),
true_(NULL),
false_(NULL),
acquired_error_(NULL) {}
~ApiState() {
- while (top_scope_ != NULL) {
- ApiLocalScope* scope = top_scope_;
- top_scope_ = top_scope_->previous();
- delete scope;
- }
if (null_ != NULL) {
persistent_handles().FreeHandle(null_);
null_ = NULL;
@@ -718,77 +692,18 @@
}
// Accessors.
- ApiLocalScope* reusable_scope() const { return reusable_scope_; }
- void set_reusable_scope(ApiLocalScope* value) {
- ASSERT(value == NULL || reusable_scope_ == NULL);
- reusable_scope_ = value;
- }
- ApiLocalScope* top_scope() const { return top_scope_; }
- void set_top_scope(ApiLocalScope* value) { top_scope_ = value; }
-
PersistentHandles& persistent_handles() { return persistent_handles_; }
FinalizablePersistentHandles& weak_persistent_handles() {
return weak_persistent_handles_;
}
- FinalizablePersistentHandles& prologue_weak_persistent_handles() {
- return prologue_weak_persistent_handles_;
- }
-
- WeakReferenceSet* delayed_weak_reference_sets() {
- return delayed_weak_reference_sets_;
- }
- void set_delayed_weak_reference_sets(WeakReferenceSet* reference_set) {
- delayed_weak_reference_sets_ = reference_set;
- }
-
- void UnwindScopes(uword stack_marker) {
- // Unwind all scopes using the same stack_marker, i.e. all scopes allocated
- // under the same top_exit_frame_info.
- while (top_scope_ != NULL &&
- top_scope_->stack_marker() != 0 &&
- top_scope_->stack_marker() == stack_marker) {
- ApiLocalScope* scope = top_scope_;
- top_scope_ = top_scope_->previous();
- delete scope;
- }
- }
-
- void VisitObjectPointers(ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_handles) {
- ApiLocalScope* scope = top_scope_;
- while (scope != NULL) {
- scope->local_handles()->VisitObjectPointers(visitor);
- scope = scope->previous();
- }
+ void VisitObjectPointers(ObjectPointerVisitor* visitor) {
persistent_handles().VisitObjectPointers(visitor);
- if (visit_prologue_weak_handles) {
- prologue_weak_persistent_handles().VisitObjectPointers(visitor);
- }
}
- void VisitWeakHandles(HandleVisitor* visitor,
- bool visit_prologue_weak_handles) {
+ void VisitWeakHandles(HandleVisitor* visitor) {
weak_persistent_handles().VisitHandles(visitor);
- if (visit_prologue_weak_handles) {
- prologue_weak_persistent_handles().VisitHandles(visitor);
- }
- }
-
- void VisitPrologueWeakHandles(HandleVisitor* visitor) {
- prologue_weak_persistent_handles().VisitHandles(visitor);
- }
-
- bool IsValidLocalHandle(Dart_Handle object) const {
- ApiLocalScope* scope = top_scope_;
- while (scope != NULL) {
- if (scope->local_handles()->IsValidHandle(object)) {
- return true;
- }
- scope = scope->previous();
- }
- return false;
}
bool IsValidPersistentHandle(Dart_PersistentHandle object) const {
@@ -799,37 +714,14 @@
return weak_persistent_handles_.IsValidHandle(object);
}
- bool IsValidPrologueWeakPersistentHandle(
- Dart_WeakPersistentHandle object) const {
- return prologue_weak_persistent_handles_.IsValidHandle(object);
- }
-
bool IsProtectedHandle(PersistentHandle* object) const {
if (object == NULL) return false;
return object == null_ || object == true_ || object == false_;
}
- int CountLocalHandles() const {
- int total = 0;
- ApiLocalScope* scope = top_scope_;
- while (scope != NULL) {
- total += scope->local_handles()->CountHandles();
- scope = scope->previous();
- }
- return total;
- }
int CountPersistentHandles() const {
return persistent_handles_.CountHandles();
}
- int ZoneSizeInBytes() const {
- int total = 0;
- ApiLocalScope* scope = top_scope_;
- while (scope != NULL) {
- total += scope->zone()->SizeInBytes();
- scope = scope->previous();
- }
- return total;
- }
void SetupAcquiredError() {
ASSERT(acquired_error_ == NULL);
@@ -845,19 +737,11 @@
return acquired_error_;
}
- WeakReferenceSetBuilder* NewWeakReferenceSetBuilder();
-
- void DelayWeakReferenceSet(WeakReferenceSet* reference_set);
-
WeakTable* acquired_table() { return &acquired_table_; }
private:
PersistentHandles persistent_handles_;
FinalizablePersistentHandles weak_persistent_handles_;
- FinalizablePersistentHandles prologue_weak_persistent_handles_;
- ApiLocalScope* reusable_scope_;
- ApiLocalScope* top_scope_;
- WeakReferenceSet* delayed_weak_reference_sets_;
WeakTable acquired_table_;
// Persistent handles to important objects.
@@ -870,123 +754,16 @@
};
-class WeakReferenceSet {
- public:
- explicit WeakReferenceSet(Zone* zone)
- : next_(NULL),
- keys_(1, zone),
- values_(1, zone) {
- }
- ~WeakReferenceSet() {}
-
- WeakReferenceSet* next() const { return next_; }
-
- intptr_t num_keys() const { return keys_.length(); }
- RawObject** get_key(intptr_t i) {
- ASSERT(i >= 0);
- ASSERT(i < num_keys());
- FinalizablePersistentHandle* ref =
- FinalizablePersistentHandle::Cast(keys_[i]);
- return ref->raw_addr();
- }
-
- intptr_t num_values() const { return values_.length(); }
- RawObject** get_value(intptr_t i) {
- ASSERT(i >= 0);
- ASSERT(i < num_values());
- FinalizablePersistentHandle* ref =
- FinalizablePersistentHandle::Cast(values_[i]);
- return ref->raw_addr();
- }
-
- bool SingletonKeyEqualsValue() const {
- ASSERT((num_keys() == 1) && (num_values() == 1));
- return (keys_[0] == values_[0]);
- }
-
- void Append(Dart_WeakPersistentHandle key, Dart_WeakPersistentHandle value) {
- keys_.Add(key);
- values_.Add(value);
- }
-
- void AppendKey(Dart_WeakPersistentHandle key) {
- keys_.Add(key);
- }
-
- void AppendValue(Dart_WeakPersistentHandle value) {
- values_.Add(value);
- }
-
- static WeakReferenceSet* Pop(WeakReferenceSet** queue) {
- ASSERT(queue != NULL);
- WeakReferenceSet* head = *queue;
- if (head != NULL) {
- *queue = head->next();
- head->next_ = NULL;
- }
- return head;
- }
-
- static void Push(WeakReferenceSet* reference_set, WeakReferenceSet** queue) {
- ASSERT(reference_set != NULL);
- ASSERT(queue != NULL);
- reference_set->next_ = *queue;
- *queue = reference_set;
- }
-
- void* operator new(uword size, Zone* zone) {
- return reinterpret_cast<void*>(zone->AllocUnsafe(size));
- }
-
- // Disallow explicit deallocation of WeakReferenceSet.
- void operator delete(void* pointer) { UNREACHABLE(); }
-
- private:
- WeakReferenceSet* next_;
- ApiGrowableArray<Dart_WeakPersistentHandle> keys_;
- ApiGrowableArray<Dart_WeakPersistentHandle> values_;
-
- DISALLOW_COPY_AND_ASSIGN(WeakReferenceSet);
-};
-
-
-class WeakReferenceSetBuilder {
- public:
- ApiState* api_state() const {
- return api_state_;
- }
-
- WeakReferenceSet* NewWeakReferenceSet() {
- return new (zone_) WeakReferenceSet(zone_);
- }
-
- private:
- explicit WeakReferenceSetBuilder(ApiState* api_state)
- : api_state_(api_state),
- zone_(api_state->top_scope()->zone()) {
- }
-
- ApiState* api_state_;
- Zone* zone_;
-
- friend class ApiState;
- DISALLOW_IMPLICIT_CONSTRUCTORS(WeakReferenceSetBuilder);
-};
-
-
inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
Isolate* isolate,
- bool is_prologue,
const Object& object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback,
intptr_t external_size) {
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- FinalizablePersistentHandle* ref = is_prologue ?
- state->prologue_weak_persistent_handles().AllocateHandle() :
+ FinalizablePersistentHandle* ref =
state->weak_persistent_handles().AllocateHandle();
- ref->SetPrologueWeakPersistent(is_prologue);
ref->set_raw(object);
ref->set_peer(peer);
ref->set_callback(callback);
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 63e2689..5a252e5 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -33,26 +33,39 @@
class ScopedIsolateStackLimits : public ValueObject {
public:
- explicit ScopedIsolateStackLimits(Isolate* isolate)
- : isolate_(isolate), stack_base_(Isolate::GetCurrentStackPointer()) {
- ASSERT(isolate_ != NULL);
- ASSERT(isolate_ == Isolate::Current());
- if (stack_base_ >= isolate_->stack_base()) {
- isolate_->SetStackLimitFromStackBase(stack_base_);
+ explicit ScopedIsolateStackLimits(Thread* thread)
+ : thread_(thread), saved_stack_limit_(0) {
+ ASSERT(thread != NULL);
+ // Set the thread's stack_base based on the current
+ // stack pointer, we keep refining this value as we
+ // see higher stack pointers (Note: we assume the stack
+ // grows from high to low addresses).
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ uword current_sp = Isolate::GetCurrentStackPointer();
+ if (current_sp > os_thread->stack_base()) {
+ os_thread->set_stack_base(current_sp);
}
+ // Save the Isolate's current stack limit and adjust the stack
+ // limit based on the thread's stack_base.
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate == Isolate::Current());
+ saved_stack_limit_ = isolate->saved_stack_limit();
+ isolate->SetStackLimitFromStackBase(os_thread->stack_base());
}
~ScopedIsolateStackLimits() {
- ASSERT(isolate_ == Isolate::Current());
- if (isolate_->stack_base() == stack_base_) {
- // Bottomed out.
- isolate_->ClearStackLimit();
- }
+ Isolate* isolate = thread_->isolate();
+ ASSERT(isolate == Isolate::Current());
+ // Since we started with a stack limit of 0 we should be getting back
+ // to a stack limit of 0 when all nested invocations are done and
+ // we have bottomed out.
+ isolate->SetStackLimit(saved_stack_limit_);
}
private:
- Isolate* isolate_;
- uword stack_base_;
+ Thread* thread_;
+ uword saved_stack_limit_;
};
@@ -84,7 +97,6 @@
// compiled.
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- Isolate* isolate = thread->isolate();
ASSERT(thread->IsMutatorThread());
if (!function.HasCode()) {
const Error& error = Error::Handle(
@@ -99,7 +111,7 @@
const Code& code = Code::Handle(zone, function.CurrentCode());
ASSERT(!code.IsNull());
ASSERT(thread->no_callback_scope_depth() == 0);
- ScopedIsolateStackLimits stack_limit(isolate);
+ ScopedIsolateStackLimits stack_limit(thread);
SuspendLongJumpScope suspend_long_jump_scope(thread);
#if defined(USING_SIMULATOR)
return bit_copy<RawObject*, int64_t>(Simulator::Current()->Call(
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0be47b7..aea2178 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -258,13 +258,19 @@
}
-bool Debugger::HasEventHandler() {
+bool Debugger::HasAnyEventHandler() {
return ((event_handler_ != NULL) ||
Service::isolate_stream.enabled() ||
Service::debug_stream.enabled());
}
+bool Debugger::HasDebugEventHandler() {
+ return ((event_handler_ != NULL) ||
+ Service::debug_stream.enabled());
+}
+
+
static bool ServiceNeedsDebuggerEvent(DebuggerEvent::EventType type) {
switch (type) {
case DebuggerEvent::kBreakpointResolved:
@@ -289,8 +295,6 @@
void Debugger::InvokeEventHandler(DebuggerEvent* event) {
- ASSERT(HasEventHandler());
-
// Give the event to the Service first, as the debugger event handler
// may go into a message loop and the Service will not.
//
@@ -301,7 +305,8 @@
Service::HandleEvent(&service_event);
}
- if (FLAG_steal_breakpoints && event->IsPauseEvent()) {
+ if ((FLAG_steal_breakpoints || (event_handler_ == NULL)) &&
+ event->IsPauseEvent()) {
// We allow the embedder's default breakpoint handler to be overridden.
isolate_->PauseEventHandler();
} else if (event_handler_ != NULL) {
@@ -325,7 +330,7 @@
void Debugger::SignalIsolateEvent(DebuggerEvent::EventType type) {
- if (HasEventHandler()) {
+ if (HasAnyEventHandler()) {
DebuggerEvent event(isolate_, type);
ASSERT(event.isolate_id() != ILLEGAL_ISOLATE_ID);
if (type == DebuggerEvent::kIsolateInterrupted) {
@@ -347,21 +352,9 @@
RawError* Debugger::SignalIsolateInterrupted() {
- if (HasEventHandler()) {
+ if (HasDebugEventHandler()) {
SignalIsolateEvent(DebuggerEvent::kIsolateInterrupted);
}
- Dart_IsolateInterruptCallback callback = isolate_->InterruptCallback();
- if (callback != NULL) {
- if (!(*callback)()) {
- if (FLAG_trace_isolates) {
- OS::Print("[!] Embedder api: terminating isolate:\n"
- "\tisolate: %s\n", isolate_->name());
- }
- const String& msg =
- String::Handle(String::New("isolate terminated by embedder"));
- return UnwindError::New(msg);
- }
- }
// If any error occurred while in the debug message loop, return it here.
const Error& error =
@@ -1120,6 +1113,7 @@
if (var_name.raw() != Symbols::AsyncOperation().raw()) {
JSONObject jsvar(&jsvars);
jsvar.AddProperty("type", "BoundVariable");
+ var_name = String::IdentifierPrettyName(var_name);
jsvar.AddProperty("name", var_name.ToCString());
jsvar.AddProperty("value", var_value, !full);
// TODO(turnidge): Do we really want to provide this on every
@@ -1410,7 +1404,7 @@
void Debugger::SignalBpResolved(Breakpoint* bpt) {
- if (HasEventHandler() && !bpt->IsSingleShot()) {
+ if (HasDebugEventHandler() && !bpt->IsSingleShot()) {
DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
event.set_breakpoint(bpt);
InvokeEventHandler(&event);
@@ -1631,7 +1625,7 @@
// interested in exception events.
if (ignore_breakpoints_ ||
IsPaused() ||
- (!HasEventHandler()) ||
+ (!HasDebugEventHandler()) ||
(exc_pause_info_ == kNoPauseOnExceptions)) {
return;
}
@@ -2615,9 +2609,6 @@
RawError* Debugger::DebuggerStepCallback() {
ASSERT(isolate_->single_step());
- // We can't get here unless the debugger event handler enabled
- // single stepping.
- ASSERT(HasEventHandler());
// Don't pause recursively.
if (IsPaused()) {
return Error::null();
@@ -2685,7 +2676,7 @@
// We ignore this breakpoint when the VM is executing code invoked
// by the debugger to evaluate variables values, or when we see a nested
// breakpoint or exception event.
- if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) {
+ if (ignore_breakpoints_ || IsPaused()) {
return Error::null();
}
DebuggerStackTrace* stack_trace = CollectStackTrace();
@@ -2774,10 +2765,14 @@
// We ignore this breakpoint when the VM is executing code invoked
// by the debugger to evaluate variables values, or when we see a nested
// breakpoint or exception event.
- if (ignore_breakpoints_ || IsPaused() || !HasEventHandler()) {
+ if (ignore_breakpoints_ || IsPaused()) {
return;
}
+ if (!HasDebugEventHandler()) {
+ OS::Print("Hit debugger!");
+ }
+
DebuggerStackTrace* stack_trace = CollectStackTrace();
ASSERT(stack_trace->Length() > 0);
ASSERT(stack_trace_ == NULL);
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index aaa2b84..acb69ec 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -584,7 +584,8 @@
kSingleStep
};
- static bool HasEventHandler();
+ static bool HasAnyEventHandler();
+ static bool HasDebugEventHandler();
void InvokeEventHandler(DebuggerEvent* event);
void FindCompiledFunctions(const Script& script,
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index bd6883c..7e1ec45 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -56,6 +56,7 @@
DART_EXPORT intptr_t Dart_CacheObject(Dart_Handle object_in) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object_in));
if (obj.IsApiError()) {
return -1;
@@ -66,11 +67,12 @@
DART_EXPORT Dart_Handle Dart_GetCachedObject(intptr_t obj_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (!I->debugger()->IsValidObjectId(obj_id)) {
return Api::NewError("%s: object id %" Pd " is invalid",
CURRENT_FUNC, obj_id);
}
- return Api::NewHandle(I, I->debugger()->GetCachedObject(obj_id));
+ return Api::NewHandle(T, I->debugger()->GetCachedObject(obj_id));
}
@@ -117,7 +119,7 @@
if (paused_event_handler != NULL) {
Dart_CodeLocation location;
ActivationFrame* top_frame = event->top_frame();
- location.script_url = Api::NewHandle(isolate, top_frame->SourceUrl());
+ location.script_url = Api::NewHandle(thread, top_frame->SourceUrl());
const Library& lib = Library::Handle(top_frame->Library());
location.library_id = lib.index();
location.token_pos = top_frame->TokenPos();
@@ -138,7 +140,7 @@
Script& script = Script::Handle(zone);
intptr_t token_pos;
bpt->bpt_location()->GetCodeLocation(&library, &script, &token_pos);
- location.script_url = Api::NewHandle(isolate, script.url());
+ location.script_url = Api::NewHandle(thread, script.url());
location.library_id = library.index();
location.token_pos = token_pos;
(*bp_resolved_handler)(isolate_id, bpt->id(), location);
@@ -146,7 +148,7 @@
} else if (event->type() == DebuggerEvent::kExceptionThrown) {
if (exc_thrown_handler != NULL) {
Dart_Handle exception =
- Api::NewHandle(isolate, event->exception()->raw());
+ Api::NewHandle(thread, event->exception()->raw());
Dart_StackTrace trace =
reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
(*exc_thrown_handler)(isolate_id, exception, trace);
@@ -199,6 +201,7 @@
DART_EXPORT Dart_Handle Dart_SetExceptionPauseInfo(
Dart_ExceptionPauseInfo pause_info) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
I->debugger()->SetExceptionPauseInfo(pause_info);
return Api::Success();
}
@@ -206,12 +209,14 @@
DART_EXPORT Dart_ExceptionPauseInfo Dart_GetExceptionPauseInfo() {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
return I->debugger()->GetExceptionPauseInfo();
}
DART_EXPORT Dart_Handle Dart_GetStackTrace(Dart_StackTrace* trace) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
CHECK_NOT_NULL(trace);
*trace = reinterpret_cast<Dart_StackTrace>(
I->debugger()->CurrentStackTrace());
@@ -231,6 +236,7 @@
if (dart_stacktrace.IsNull()) {
*trace = NULL;
} else {
+ Isolate* I = T->isolate();
*trace = reinterpret_cast<Dart_StackTrace>(
I->debugger()->StackTraceFrom(dart_stacktrace));
}
@@ -251,10 +257,10 @@
DARTSCOPE(Thread::Current());
CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
if (function_name != NULL) {
- *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
+ *function_name = Api::NewHandle(T, frame->QualifiedFunctionName());
}
if (script_url != NULL) {
- *script_url = Api::NewHandle(I, frame->SourceUrl());
+ *script_url = Api::NewHandle(T, frame->SourceUrl());
}
if (line_number != NULL) {
*line_number = frame->LineNumber();
@@ -276,14 +282,14 @@
DARTSCOPE(Thread::Current());
CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
if (function_name != NULL) {
- *function_name = Api::NewHandle(I, frame->QualifiedFunctionName());
+ *function_name = Api::NewHandle(T, frame->QualifiedFunctionName());
}
if (function != NULL) {
- *function = Api::NewHandle(I, frame->function().raw());
+ *function = Api::NewHandle(T, frame->function().raw());
}
if (location != NULL) {
- location->script_url = Api::NewHandle(I, frame->SourceUrl());
+ location->script_url = Api::NewHandle(T, frame->SourceUrl());
const Library& lib = Library::Handle(Z, frame->Library());
location->library_id = lib.index();
location->token_pos = frame->TokenPos();
@@ -320,7 +326,7 @@
Dart_ActivationFrame activation_frame) {
DARTSCOPE(Thread::Current());
CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
- return Api::NewHandle(I, frame->GetLocalVariables());
+ return Api::NewHandle(T, frame->GetLocalVariables());
}
@@ -328,6 +334,7 @@
Dart_Handle script_url_in,
intptr_t line_number) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
UNWRAP_AND_CHECK_PARAM(String, script_url, script_url_in);
Debugger* debugger = I->debugger();
@@ -343,6 +350,7 @@
DART_EXPORT Dart_Handle Dart_GetBreakpointURL(intptr_t bp_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
Debugger* debugger = I->debugger();
Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
@@ -350,12 +358,13 @@
return Api::NewError("%s: breakpoint with id %" Pd " does not exist",
CURRENT_FUNC, bp_id);
}
- return Api::NewHandle(I, bpt->bpt_location()->url());
+ return Api::NewHandle(T, bpt->bpt_location()->url());
}
DART_EXPORT Dart_Handle Dart_GetBreakpointLine(intptr_t bp_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
Debugger* debugger = I->debugger();
Breakpoint* bpt = debugger->GetBreakpointById(bp_id);
@@ -376,6 +385,7 @@
Dart_Handle class_name_in,
Dart_Handle function_name_in) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -415,6 +425,7 @@
Dart_Handle class_name_in,
Dart_Handle function_name_in) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
UNWRAP_AND_CHECK_PARAM(Library, library, library_in);
UNWRAP_AND_CHECK_PARAM(String, class_name, class_name_in);
UNWRAP_AND_CHECK_PARAM(String, function_name, function_name_in);
@@ -442,7 +453,7 @@
const Error& error = Error::Handle(Z,
debugger->OneTimeBreakAtEntry(bp_target));
if (!error.IsNull()) {
- return Api::NewHandle(I, error.raw());
+ return Api::NewHandle(T, error.raw());
}
return Api::Success();
}
@@ -450,6 +461,7 @@
DART_EXPORT Dart_Handle Dart_RemoveBreakpoint(intptr_t bp_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
I->debugger()->RemoveBreakpoint(bp_id);
return Api::Success();
}
@@ -457,6 +469,7 @@
DART_EXPORT Dart_Handle Dart_SetStepOver() {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
I->debugger()->SetStepOver();
return Api::Success();
}
@@ -464,6 +477,7 @@
DART_EXPORT Dart_Handle Dart_SetStepInto() {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
I->debugger()->SetSingleStep();
return Api::Success();
}
@@ -471,6 +485,7 @@
DART_EXPORT Dart_Handle Dart_SetStepOut() {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
I->debugger()->SetStepOut();
return Api::Success();
}
@@ -478,44 +493,48 @@
DART_EXPORT Dart_Handle Dart_GetInstanceFields(Dart_Handle object_in) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
- return Api::NewHandle(I, I->debugger()->GetInstanceFields(obj));
+ return Api::NewHandle(T, I->debugger()->GetInstanceFields(obj));
}
DART_EXPORT Dart_Handle Dart_GetStaticFields(Dart_Handle target) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Type& type_obj = Api::UnwrapTypeHandle(Z, target);
if (type_obj.IsNull()) {
return Api::NewError("%s expects argument 'target' to be a type",
CURRENT_FUNC);
}
const Class& cls = Class::Handle(Z, type_obj.type_class());
- return Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
+ return Api::NewHandle(T, I->debugger()->GetStaticFields(cls));
}
DART_EXPORT Dart_Handle Dart_GetLibraryFields(intptr_t library_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& lib =
Library::Handle(Z, Library::GetLibrary(library_id));
if (lib.IsNull()) {
return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
- return Api::NewHandle(I, I->debugger()->GetLibraryFields(lib));
+ return Api::NewHandle(T, I->debugger()->GetLibraryFields(lib));
}
DART_EXPORT Dart_Handle Dart_GetGlobalVariables(intptr_t library_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const Library& lib = Library::Handle(Z, Library::GetLibrary(library_id));
if (lib.IsNull()) {
return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
- return Api::NewHandle(I, I->debugger()->GetGlobalFields(lib));
+ return Api::NewHandle(T, I->debugger()->GetGlobalFields(lib));
}
@@ -525,7 +544,7 @@
DARTSCOPE(Thread::Current());
CHECK_AND_CAST(ActivationFrame, frame, activation_frame);
UNWRAP_AND_CHECK_PARAM(String, expr, expr_in);
- return Api::NewHandle(I, frame->Evaluate(expr));
+ return Api::NewHandle(T, frame->Evaluate(expr));
}
@@ -543,22 +562,22 @@
// Type extends Instance, must check first.
if (target.IsType()) {
const Class& cls = Class::Handle(Z, Type::Cast(target).type_class());
- return Api::NewHandle(I, cls.Evaluate(expr,
+ return Api::NewHandle(T, cls.Evaluate(expr,
Array::empty_array(),
Array::empty_array()));
} else if (target.IsInstance()) {
const Instance& inst = Instance::Cast(target);
- return Api::NewHandle(I, inst.Evaluate(expr,
+ return Api::NewHandle(T, inst.Evaluate(expr,
Array::empty_array(),
Array::empty_array()));
} else if (target.IsLibrary()) {
const Library& lib = Library::Cast(target);
- return Api::NewHandle(I, lib.Evaluate(expr,
+ return Api::NewHandle(T, lib.Evaluate(expr,
Array::empty_array(),
Array::empty_array()));
} else if (target.IsClass()) {
const Class& cls = Class::Cast(target);
- return Api::NewHandle(I, cls.Evaluate(expr,
+ return Api::NewHandle(T, cls.Evaluate(expr,
Array::empty_array(),
Array::empty_array()));
}
@@ -569,7 +588,7 @@
DART_EXPORT Dart_Handle Dart_GetObjClass(Dart_Handle object_in) {
DARTSCOPE(Thread::Current());
UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
- return Api::NewHandle(I, obj.GetType());
+ return Api::NewHandle(T, obj.GetType());
}
@@ -585,11 +604,12 @@
DART_EXPORT Dart_Handle Dart_GetClassFromId(intptr_t class_id) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (!I->class_table()->IsValidIndex(class_id)) {
return Api::NewError("%s: %" Pd " is not a valid class id",
CURRENT_FUNC, class_id);
}
- return Api::NewHandle(I, I->class_table()->At(class_id));
+ return Api::NewHandle(T, I->class_table()->At(class_id));
}
@@ -613,7 +633,7 @@
if (type.IsNull()) {
return Dart_Null();
}
- return Api::NewHandle(I, type.Canonicalize());
+ return Api::NewHandle(T, type.Canonicalize());
}
// Set up the type arguments array for the super class type.
const Class& super_cls = Class::Handle(cls.SuperClass());
@@ -635,7 +655,7 @@
Type::New(super_cls, super_type_args_array, Scanner::kNoSourcePos));
ASSERT(!instantiated_type.IsNull());
instantiated_type.SetIsFinalized();
- return Api::NewHandle(I, instantiated_type.Canonicalize());
+ return Api::NewHandle(T, instantiated_type.Canonicalize());
}
@@ -654,10 +674,10 @@
const Function& func = Function::Handle(Closure::function(instance));
ASSERT(!func.IsNull());
if (name != NULL) {
- *name = Api::NewHandle(I, func.QualifiedUserVisibleName());
+ *name = Api::NewHandle(T, func.QualifiedUserVisibleName());
}
if (signature != NULL) {
- *signature = Api::NewHandle(I, func.UserVisibleSignature());
+ *signature = Api::NewHandle(T, func.UserVisibleSignature());
}
if (location != NULL) {
@@ -669,11 +689,11 @@
// Note func.script() is not the same as cls.script() for eval functions.
const Script& script = Script::Handle(Z, func.script());
ASSERT(!script.IsNull());
- location->script_url = Api::NewHandle(I, script.url());
+ location->script_url = Api::NewHandle(T, script.url());
location->library_id = lib.index();
location->token_pos = func.token_pos();
} else {
- location->script_url = Api::NewHandle(I, String::null());
+ location->script_url = Api::NewHandle(T, String::null());
location->library_id = -1;
location->token_pos = -1;
}
@@ -689,13 +709,14 @@
intptr_t* super_class_id,
Dart_Handle* static_fields) {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
if (!I->class_table()->IsValidIndex(cls_id)) {
return Api::NewError("%s: %" Pd " is not a valid class id",
CURRENT_FUNC, cls_id);
}
Class& cls = Class::Handle(Z, I->class_table()->At(cls_id));
if (class_name != NULL) {
- *class_name = Api::NewHandle(I, cls.Name());
+ *class_name = Api::NewHandle(T, cls.Name());
}
if (library_id != NULL) {
const Library& lib = Library::Handle(Z, cls.library());
@@ -710,7 +731,7 @@
}
if (static_fields != NULL) {
*static_fields =
- Api::NewHandle(I, I->debugger()->GetStaticFields(cls));
+ Api::NewHandle(T, I->debugger()->GetStaticFields(cls));
}
return Api::Success();
}
@@ -732,7 +753,7 @@
CURRENT_FUNC, script_url.ToCString(),
String::Handle(lib.url()).ToCString());
}
- return Api::NewHandle(I, script.Source());
+ return Api::NewHandle(T, script.Source());
}
@@ -755,7 +776,7 @@
const GrowableObjectArray& info =
GrowableObjectArray::Handle(script.GenerateLineNumberArray());
- return Api::NewHandle(I, Array::MakeArray(info));
+ return Api::NewHandle(T, Array::MakeArray(info));
}
@@ -778,7 +799,7 @@
library_url.ToCString());
}
- return Api::NewHandle(I, script.GenerateSource());
+ return Api::NewHandle(T, script.GenerateSource());
}
@@ -802,12 +823,13 @@
url = script.url();
script_list.SetAt(i, url);
}
- return Api::NewHandle(I, script_list.raw());
+ return Api::NewHandle(T, script_list.raw());
}
DART_EXPORT Dart_Handle Dart_GetLibraryIds() {
DARTSCOPE(Thread::Current());
+ Isolate* I = T->isolate();
const GrowableObjectArray& libs =
GrowableObjectArray::Handle(Z, I->object_store()->libraries());
@@ -822,7 +844,7 @@
ASSERT(Smi::IsValid(lib.index()));
library_id_list.SetAt(i, Smi::Handle(Smi::New(lib.index())));
}
- return Api::NewHandle(I, library_id_list.raw());
+ return Api::NewHandle(T, library_id_list.raw());
}
@@ -833,7 +855,7 @@
return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
- return Api::NewHandle(I, lib.raw());
+ return Api::NewHandle(T, lib.raw());
}
@@ -885,7 +907,7 @@
import_list.Add(Smi::Handle(Smi::New(imported.index())));
}
}
- return Api::NewHandle(I, Array::MakeArray(import_list));
+ return Api::NewHandle(T, Array::MakeArray(import_list));
}
@@ -896,7 +918,7 @@
return Api::NewError("%s: %" Pd " is not a valid library id",
CURRENT_FUNC, library_id);
}
- return Api::NewHandle(I, lib.url());
+ return Api::NewHandle(T, lib.url());
}
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 1bfc4ce..cd1b8c8 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1515,7 +1515,7 @@
sync = new Monitor();
EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
Dart_SetPausedEventHandler(InterruptIsolateHandler);
- int result = OSThread::Start(InterruptIsolateRun, 0);
+ int result = OSThread::Start("DebugInterruptIsolate", InterruptIsolateRun, 0);
EXPECT_EQ(0, result);
// Wait for the test isolate to be created.
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index f38639f..c1ec041 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -288,8 +288,8 @@
if (*equals != '=') {
// No explicit option argument. Determine if there is a "no_" prefix
// preceding the name.
- const char* kNo1Prefix = "no_";
- const char* kNo2Prefix = "no-";
+ const char* const kNo1Prefix = "no_";
+ const char* const kNo2Prefix = "no-";
const intptr_t kNo1PrefixLen = strlen(kNo1Prefix);
const intptr_t kNo2PrefixLen = strlen(kNo2Prefix);
if (strncmp(option, kNo1Prefix, kNo1PrefixLen) == 0) {
@@ -359,7 +359,7 @@
qsort(flags_, num_flags_, sizeof flags_[0], CompareFlagNames);
- const char* kPrefix = "--";
+ const char* const kPrefix = "--";
const intptr_t kPrefixLen = strlen(kPrefix);
int i = 0;
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index e40887b..6d47957 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -103,8 +103,8 @@
// loading, deoptimization, ...). Noopt mode simulates behavior
// of precompiled code, therefore do not allow recompilation.
Compiler::set_allow_recompilation(false);
- // TODO(srdjan): Enable CHA deoptimization when eager class finalization is
- // implemented, either with precompilation or as a special pass.
+ // Precompilation finalizes all classes and thus allows CHA optimizations.
+ // Do not require CHA triggered deoptimization.
FLAG_use_cha_deopt = false;
// Calling the PrintStopMessage stub is not supported in precompiled code
// since it is done at places where no pool pointer is loaded.
@@ -546,11 +546,6 @@
#endif
}
- if (inline_id_to_function_.length() > max_inlining_id + 1) {
- // TODO(srdjan): Some inlined function can disappear,
- // truncate 'inline_id_to_function_'.
- }
-
if (is_optimizing()) {
LogBlock lb;
intervals.Add(IntervalStruct(prev_offset, prev_inlining_id));
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 448b70a..ded5e74 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1312,7 +1312,7 @@
__ lw(T0, Address(SP, (argument_count - 1) * kWordSize));
if (ic_data.NumArgsTested() == 1) {
__ LoadUniqueObject(S5, ic_data);
- __ BranchLink(*StubCode::ICLookup_entry());
+ __ BranchLinkPatchable(*StubCode::ICLookup_entry());
} else {
const String& name = String::Handle(zone(), ic_data.target_name());
const Array& arguments_descriptor =
@@ -1323,7 +1323,7 @@
MegamorphicCacheTable::Lookup(isolate(), name, arguments_descriptor));
__ LoadUniqueObject(S5, cache);
- __ BranchLink(*StubCode::MegamorphicLookup_entry());
+ __ BranchLinkPatchable(*StubCode::MegamorphicLookup_entry());
}
__ jalr(T1);
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 930da8d..7cd46a0 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -11,6 +11,7 @@
#include "vm/flow_graph_builder.h"
#include "vm/flow_graph_compiler.h"
#include "vm/flow_graph_optimizer.h"
+#include "vm/flow_graph_type_propagator.h"
#include "vm/il_printer.h"
#include "vm/intrinsifier.h"
#include "vm/longjump.h"
@@ -776,10 +777,19 @@
{
CSTAT_TIMER_SCOPE(thread(), graphinliner_opt_timer);
- // TODO(zerny): Do more optimization passes on the callee graph.
- FlowGraphOptimizer optimizer(callee_graph);
+ // TODO(fschneider): Improve suppression of speculative inlining.
+ // Deopt-ids overlap between caller and callee.
+ FlowGraphOptimizer optimizer(callee_graph,
+ inliner_->use_speculative_inlining_,
+ inliner_->inlining_black_list_);
if (Compiler::always_optimize()) {
optimizer.PopulateWithICData();
+
+ optimizer.ApplyClassIds();
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
+
+ FlowGraphTypePropagator::Propagate(callee_graph);
+ DEBUG_ASSERT(callee_graph->VerifyUseLists());
}
optimizer.ApplyICData();
DEBUG_ASSERT(callee_graph->VerifyUseLists());
@@ -1469,7 +1479,9 @@
bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid,
const Function& target) {
- FlowGraphOptimizer optimizer(owner_->caller_graph());
+ FlowGraphOptimizer optimizer(owner_->caller_graph(),
+ false, // Speculative inlining not applicable.
+ NULL);
TargetEntryInstr* entry;
Definition* last;
// Replace the receiver argument with a redefinition to prevent code from
@@ -1775,11 +1787,16 @@
FlowGraphInliner::FlowGraphInliner(
FlowGraph* flow_graph,
GrowableArray<const Function*>* inline_id_to_function,
- GrowableArray<intptr_t>* caller_inline_id)
+ GrowableArray<intptr_t>* caller_inline_id,
+ bool use_speculative_inlining,
+ GrowableArray<intptr_t>* inlining_black_list)
: flow_graph_(flow_graph),
inline_id_to_function_(inline_id_to_function),
caller_inline_id_(caller_inline_id),
- trace_inlining_(ShouldTraceInlining(flow_graph)) {
+ trace_inlining_(ShouldTraceInlining(flow_graph)),
+ use_speculative_inlining_(use_speculative_inlining),
+ inlining_black_list_(inlining_black_list) {
+ ASSERT(!use_speculative_inlining || (inlining_black_list != NULL));
}
@@ -1819,7 +1836,7 @@
// Use function name to determine if inlineable operator.
-// TODO(srdjan): add names as necessary
+// Add names as necessary.
static bool IsInlineableOperator(const Function& function) {
return (function.name() == Symbols::IndexToken().raw()) ||
(function.name() == Symbols::AssignIndexToken().raw()) ||
@@ -1839,7 +1856,8 @@
if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
function.IsImplicitSetterFunction() || function.IsSetterFunction() ||
- IsInlineableOperator(function)) {
+ IsInlineableOperator(function) ||
+ (function.kind() == RawFunction::kConstructor)) {
const intptr_t count = function.optimized_instruction_count();
if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
return true;
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index 114348b..6e3ce09 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -18,7 +18,9 @@
public:
FlowGraphInliner(FlowGraph* flow_graph,
GrowableArray<const Function*>* inline_id_to_function,
- GrowableArray<intptr_t>* caller_inline_id);
+ GrowableArray<intptr_t>* caller_inline_id,
+ bool use_speculative_inlining,
+ GrowableArray<intptr_t>* inlining_black_list);
// The flow graph is destructively updated upon inlining.
void Inline();
@@ -41,6 +43,8 @@
GrowableArray<const Function*>* inline_id_to_function_;
GrowableArray<intptr_t>* caller_inline_id_;
const bool trace_inlining_;
+ const bool use_speculative_inlining_;
+ GrowableArray<intptr_t>* inlining_black_list_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
};
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index feb72c1..15642fc 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -18,6 +18,7 @@
#include "vm/intermediate_language.h"
#include "vm/object_store.h"
#include "vm/parser.h"
+#include "vm/precompiler.h"
#include "vm/resolver.h"
#include "vm/scopes.h"
#include "vm/stack_frame.h"
@@ -49,12 +50,14 @@
DEFINE_FLAG(bool, trace_smi_widening, false, "Trace Smi->Int32 widening pass.");
#endif
+DECLARE_FLAG(bool, precompilation);
DECLARE_FLAG(bool, polymorphic_with_deopt);
DECLARE_FLAG(bool, source_lines);
DECLARE_FLAG(bool, trace_cha);
DECLARE_FLAG(bool, trace_field_guards);
DECLARE_FLAG(bool, trace_type_check_elimination);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
+DECLARE_FLAG(bool, fields_may_be_reset);
// Quick access to the current isolate and zone.
#define I (isolate())
@@ -266,12 +269,32 @@
Resolver::ResolveDynamicForReceiverClass(owner_class,
call->function_name(),
args_desc));
- if (function.IsNull()) {
- return false;
+ if (!function.IsNull()) {
+ const ICData& ic_data = ICData::ZoneHandle(Z,
+ ICData::NewFrom(*call->ic_data(), class_ids.length()));
+ ic_data.AddReceiverCheck(owner_class.id(), function);
+ call->set_ic_data(&ic_data);
+ return true;
}
+ }
+ }
+
+ if (FLAG_precompilation &&
+ (isolate()->object_store()->unique_dynamic_targets() != Array::null())) {
+ // Check if the target is unique.
+ Function& target_function = Function::Handle(Z);
+ Precompiler::GetUniqueDynamicTarget(
+ isolate(), call->function_name(), &target_function);
+ // Calls with named arguments must be resolved/checked at runtime.
+ String& error_message = String::Handle(Z);
+ if (!target_function.IsNull() &&
+ !target_function.HasOptionalNamedParameters() &&
+ target_function.AreValidArgumentCounts(call->ArgumentCount(), 0,
+ &error_message)) {
+ const intptr_t cid = Class::Handle(Z, target_function.Owner()).id();
const ICData& ic_data = ICData::ZoneHandle(Z,
- ICData::NewFrom(*call->ic_data(), class_ids.length()));
- ic_data.AddReceiverCheck(owner_class.id(), function);
+ ICData::NewFrom(*call->ic_data(), 1));
+ ic_data.AddReceiverCheck(cid, target_function);
call->set_ic_data(&ic_data);
return true;
}
@@ -959,12 +982,11 @@
if (ic_data.NumArgsTested() != 2) {
return false;
}
- Function& target = Function::Handle();
const intptr_t len = ic_data.NumberOfChecks();
GrowableArray<intptr_t> class_ids;
for (intptr_t i = 0; i < len; i++) {
if (ic_data.IsUsedAt(i)) {
- ic_data.GetCheckAt(i, &class_ids, &target);
+ ic_data.GetClassIdsAt(i, &class_ids);
ASSERT(class_ids.length() == 2);
if (!ClassIdIsOneOf(class_ids[0], receiver_class_ids) ||
!ClassIdIsOneOf(class_ids[1], argument_class_ids)) {
@@ -982,12 +1004,11 @@
if (ic_data.NumArgsTested() != 2) {
return false;
}
- Function& target = Function::Handle();
const intptr_t len = ic_data.NumberOfChecks();
for (intptr_t i = 0; i < len; i++) {
if (ic_data.IsUsedAt(i)) {
GrowableArray<intptr_t> class_ids;
- ic_data.GetCheckAt(i, &class_ids, &target);
+ ic_data.GetClassIdsAt(i, &class_ids);
ASSERT(class_ids.length() == 2);
if ((class_ids[0] == receiver_class_id) &&
(class_ids[1] == argument_class_id)) {
@@ -2358,9 +2379,8 @@
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
ASSERT(ic_data.HasOneTarget());
- Function& target = Function::Handle(Z);
GrowableArray<intptr_t> class_ids;
- ic_data.GetCheckAt(0, &class_ids, &target);
+ ic_data.GetClassIdsAt(0, &class_ids);
ASSERT(class_ids.length() == 1);
// Inline implicit instance getter.
const String& field_name =
@@ -4839,6 +4859,7 @@
instr_it.Advance()) {
BinarySmiOpInstr* smi_op = instr_it.Current()->AsBinarySmiOp();
if ((smi_op != NULL) &&
+ smi_op->HasSSATemp() &&
BenefitsFromWidening(smi_op) &&
CanBeWidened(smi_op)) {
candidates.Add(smi_op);
@@ -5655,8 +5676,13 @@
return "<?>";
}
- bool IsFinalField() const {
- return (kind() == kField) && field().is_final();
+ // Fields that are considered immutable by load optimization.
+ // Handle static finals as non-final with precompilation because
+ // they may be reset to uninitialized after compilation.
+ bool IsImmutableField() const {
+ return (kind() == kField)
+ && field().is_final()
+ && (!field().is_static() || !FLAG_fields_may_be_reset);
}
intptr_t Hashcode() const {
@@ -5993,7 +6019,7 @@
// Compute least generic alias for the place and assign alias id to it.
void AddRepresentative(Place* place) {
- if (!place->IsFinalField()) {
+ if (!place->IsImmutableField()) {
const Place* alias = CanonicalizeAlias(place->ToAlias());
EnsureSet(&representatives_, alias->id())->Add(place->id());
@@ -6199,7 +6225,7 @@
// This essentially means that no stores to the same location can
// occur in other functions.
bool IsIndependentFromEffects(Place* place) {
- if (place->IsFinalField()) {
+ if (place->IsImmutableField()) {
// Note that we can't use LoadField's is_immutable attribute here because
// some VM-fields (those that have no corresponding Field object and
// accessed through offset alone) can share offset but have different
@@ -6633,7 +6659,7 @@
aliased_set_->LookupAliasId(place.ToAlias());
if (alias_id != AliasedSet::kNoAlias) {
killed = aliased_set_->GetKilledSet(alias_id);
- } else if (!place.IsFinalField()) {
+ } else if (!place.IsImmutableField()) {
// We encountered unknown alias: this means intrablock load
// forwarding refined parameter of this store, for example
//
@@ -7537,7 +7563,7 @@
bool is_load = false;
bool is_store = false;
Place place(instr, &is_load, &is_store);
- if (place.IsFinalField()) {
+ if (place.IsImmutableField()) {
// Loads/stores of final fields do not participate.
continue;
}
@@ -7626,7 +7652,7 @@
bool is_store = false;
Place place(instr, &is_load, &is_store);
ASSERT(!is_load && is_store);
- if (place.IsFinalField()) {
+ if (place.IsImmutableField()) {
// Final field do not participate in dead store elimination.
continue;
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 4a28be0..9d500aa 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -16,10 +16,10 @@
class FlowGraphOptimizer : public FlowGraphVisitor {
public:
- explicit FlowGraphOptimizer(
+ FlowGraphOptimizer(
FlowGraph* flow_graph,
- bool use_speculative_inlining = false,
- GrowableArray<intptr_t>* inlining_black_list = NULL)
+ bool use_speculative_inlining,
+ GrowableArray<intptr_t>* inlining_black_list)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
flow_graph_(flow_graph),
use_speculative_inlining_(use_speculative_inlining),
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 986615f..60c20aef 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -17,6 +17,7 @@
DECLARE_FLAG(bool, propagate_types);
DECLARE_FLAG(bool, trace_cha);
DECLARE_FLAG(bool, use_cha_deopt);
+DECLARE_FLAG(bool, fields_may_be_reset);
void FlowGraphTypePropagator::Propagate(FlowGraph* flow_graph) {
@@ -149,8 +150,6 @@
}
}
- HandleBranchOnStrictCompare(block);
-
for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
PropagateRecursive(block->dominated_blocks()[i]);
}
@@ -159,61 +158,6 @@
}
-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();
@@ -1009,7 +953,7 @@
abstract_type = &AbstractType::ZoneHandle(field.type());
}
ASSERT(field.is_static());
- if (field.is_final()) {
+ if (field.is_final() && !FLAG_fields_may_be_reset) {
const Instance& obj = Instance::Handle(field.StaticValue());
if ((obj.raw() != Object::sentinel().raw()) &&
(obj.raw() != Object::transition_sentinel().raw()) &&
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
index 4b1baf4..3c10917 100644
--- a/runtime/vm/flow_graph_type_propagator.h
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -20,7 +20,6 @@
void Propagate();
void PropagateRecursive(BlockEntryInstr* block);
- void HandleBranchOnStrictCompare(BlockEntryInstr* block);
void RollbackTo(intptr_t rollback_point);
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index 2e63be3..45e84d2 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -499,12 +499,10 @@
void GCMarker::IterateRoots(Isolate* isolate,
ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles,
intptr_t slice_index, intptr_t num_slices) {
ASSERT(0 <= slice_index && slice_index < num_slices);
if ((slice_index == 0) || (num_slices <= 1)) {
isolate->VisitObjectPointers(visitor,
- visit_prologue_weak_persistent_handles,
StackFrameIterator::kDontValidateFrames);
}
if ((slice_index == 1) || (num_slices <= 1)) {
@@ -516,73 +514,10 @@
}
-void GCMarker::IterateWeakRoots(Isolate* isolate,
- HandleVisitor* visitor,
- bool visit_prologue_weak_persistent_handles) {
+void GCMarker::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) {
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- isolate->VisitWeakPersistentHandles(visitor,
- visit_prologue_weak_persistent_handles);
-}
-
-
-template<class MarkingVisitorType>
-void GCMarker::IterateWeakReferences(Isolate* isolate,
- MarkingVisitorType* visitor) {
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- while (true) {
- WeakReferenceSet* queue = state->delayed_weak_reference_sets();
- if (queue == NULL) {
- // The delay queue is empty therefore no clean-up is required.
- return;
- }
- state->set_delayed_weak_reference_sets(NULL);
- while (queue != NULL) {
- WeakReferenceSet* reference_set = WeakReferenceSet::Pop(&queue);
- ASSERT(reference_set != NULL);
- intptr_t num_keys = reference_set->num_keys();
- intptr_t num_values = reference_set->num_values();
- if ((num_keys == 1) && (num_values == 1) &&
- reference_set->SingletonKeyEqualsValue()) {
- // We do not have to process sets that have just one key/value pair
- // and the key and value are identical.
- continue;
- }
- bool is_unreachable = true;
- // Test each key object for reachability. If a key object is
- // reachable, all value objects should be marked.
- for (intptr_t k = 0; k < num_keys; ++k) {
- if (!IsUnreachable(*reference_set->get_key(k))) {
- for (intptr_t v = 0; v < num_values; ++v) {
- visitor->VisitPointer(reference_set->get_value(v));
- }
- is_unreachable = false;
- // Since we have found a key object that is reachable and all
- // value objects have been marked we can break out of iterating
- // this set and move on to the next set.
- break;
- }
- }
- // If all key objects are unreachable put the reference on a
- // delay queue. This reference will be revisited if another
- // reference is marked.
- if (is_unreachable) {
- state->DelayWeakReferenceSet(reference_set);
- }
- }
- if (!visitor->DrainMarkingStack()) {
- // Break out of the loop if there has been no forward process.
- // All key objects in the weak reference sets are unreachable
- // so we reset the weak reference sets queue.
- state->set_delayed_weak_reference_sets(NULL);
- break;
- }
- }
- ASSERT(state->delayed_weak_reference_sets() == NULL);
- // All weak reference sets are zone allocated and unmarked references which
- // were on the delay queue will be freed when the zone is released in the
- // epilog callback.
+ isolate->VisitWeakPersistentHandles(visitor);
}
@@ -643,7 +578,6 @@
DelaySet* delay_set,
ThreadBarrier* barrier,
bool collect_code,
- bool visit_prologue_weak_persistent_handles,
intptr_t task_index,
intptr_t num_tasks,
uintptr_t* num_busy)
@@ -655,8 +589,6 @@
delay_set_(delay_set),
barrier_(barrier),
collect_code_(collect_code),
- visit_prologue_weak_persistent_handles_(
- visit_prologue_weak_persistent_handles),
task_index_(task_index),
num_tasks_(num_tasks),
num_busy_(num_busy) {
@@ -672,9 +604,7 @@
SyncMarkingVisitor visitor(isolate_, heap_, page_space_, marking_stack_,
delay_set_, skipped_code_functions);
// Phase 1: Iterate over roots and drain marking stack in tasks.
- marker_->IterateRoots(isolate_, &visitor,
- visit_prologue_weak_persistent_handles_,
- task_index_, num_tasks_);
+ marker_->IterateRoots(isolate_, &visitor, task_index_, num_tasks_);
do {
visitor.DrainMarkingStack();
@@ -723,7 +653,6 @@
DelaySet* delay_set_;
ThreadBarrier* barrier_;
bool collect_code_;
- bool visit_prologue_weak_persistent_handles_;
const intptr_t task_index_;
const intptr_t num_tasks_;
uintptr_t* num_busy_;
@@ -764,7 +693,6 @@
Zone* zone = stack_zone.GetZone();
MarkingStack marking_stack;
DelaySet delay_set;
- const bool visit_prologue_weak_persistent_handles = !invoke_api_callbacks;
marked_bytes_ = 0;
const int num_tasks = FLAG_marker_tasks;
if (num_tasks == 0) {
@@ -773,13 +701,10 @@
collect_code ? new(zone) SkippedCodeFunctions() : NULL;
UnsyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
&delay_set, skipped_code_functions);
- IterateRoots(isolate, &mark, visit_prologue_weak_persistent_handles,
- 0, 1);
+ IterateRoots(isolate, &mark, 0, 1);
mark.DrainMarkingStack();
- IterateWeakReferences(isolate, &mark);
MarkingWeakVisitor mark_weak;
- IterateWeakRoots(isolate, &mark_weak,
- !visit_prologue_weak_persistent_handles);
+ IterateWeakRoots(isolate, &mark_weak);
// All marking done; detach code, etc.
FinalizeResultsFrom(&mark);
} else {
@@ -791,7 +716,6 @@
MarkTask* mark_task =
new MarkTask(this, isolate, heap_, page_space, &marking_stack,
&delay_set, &barrier, collect_code,
- visit_prologue_weak_persistent_handles,
i, num_tasks, &num_busy);
ThreadPool* pool = Dart::thread_pool();
pool->Run(mark_task);
@@ -803,10 +727,8 @@
collect_code ? new(zone) SkippedCodeFunctions() : NULL;
SyncMarkingVisitor mark(isolate, heap_, page_space, &marking_stack,
&delay_set, skipped_code_functions);
- IterateWeakReferences(isolate, &mark);
MarkingWeakVisitor mark_weak;
- IterateWeakRoots(isolate, &mark_weak,
- !visit_prologue_weak_persistent_handles);
+ IterateWeakRoots(isolate, &mark_weak);
barrier.Sync();
// Phase 3: Finalize results from all markers (detach code, etc.).
diff --git a/runtime/vm/gc_marker.h b/runtime/vm/gc_marker.h
index 93b209a..f1e473a 100644
--- a/runtime/vm/gc_marker.h
+++ b/runtime/vm/gc_marker.h
@@ -38,11 +38,8 @@
void Epilogue(Isolate* isolate, bool invoke_api_callbacks);
void IterateRoots(Isolate* isolate,
ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles,
intptr_t slice_index, intptr_t num_slices);
- void IterateWeakRoots(Isolate* isolate,
- HandleVisitor* visitor,
- bool visit_prologue_weak_persistent_handles);
+ void IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor);
template<class MarkingVisitorType>
void IterateWeakReferences(Isolate* isolate, MarkingVisitorType* visitor);
void ProcessWeakTables(PageSpace* page_space);
diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h
index 77e486a..f5eef18 100644
--- a/runtime/vm/globals.h
+++ b/runtime/vm/globals.h
@@ -27,8 +27,8 @@
const intptr_t kSmiMax = (static_cast<intptr_t>(1) << kSmiBits) - 1;
const intptr_t kSmiMin = -(static_cast<intptr_t>(1) << kSmiBits);
-const double kPosInfinity = bit_cast<double>(DART_UINT64_C(0x7ff0000000000000));
-const double kNegInfinity = bit_cast<double>(DART_UINT64_C(0xfff0000000000000));
+#define kPosInfinity bit_cast<double>(DART_UINT64_C(0x7ff0000000000000))
+#define kNegInfinity bit_cast<double>(DART_UINT64_C(0xfff0000000000000))
// The expression ARRAY_SIZE(array) is a compile-time constant of type
// size_t which represents the number of elements of the given
diff --git a/runtime/vm/guard_field_test.cc b/runtime/vm/guard_field_test.cc
index 6d8c47c..d0ecb6e 100644
--- a/runtime/vm/guard_field_test.cc
+++ b/runtime/vm/guard_field_test.cc
@@ -4,7 +4,6 @@
#include "vm/dart_api_impl.h"
#include "vm/dart_api_state.h"
-#include "vm/intermediate_language.h"
#include "vm/object.h"
#include "vm/unit_test.h"
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 4b38ab3..52d5ce9 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -398,7 +398,8 @@
EffectSet LoadStaticFieldInstr::Dependencies() const {
- return StaticField().is_final() ? EffectSet::None() : EffectSet::All();
+ return (StaticField().is_final() && !FLAG_fields_may_be_reset)
+ ? EffectSet::None() : EffectSet::All();
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 6d20157..f8133ef 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -7,7 +7,7 @@
#include "include/dart_api.h"
#include "include/dart_native_api.h"
#include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
#include "vm/class_finalizer.h"
#include "vm/code_observers.h"
#include "vm/compiler.h"
@@ -631,14 +631,6 @@
}
}
- // Invoke the isolate's unhandled exception callback if there is one.
- if (Isolate::UnhandledExceptionCallback() != NULL) {
- Dart_EnterScope();
- Dart_Handle error = Api::NewHandle(I, result.raw());
- (Isolate::UnhandledExceptionCallback())(error);
- Dart_ExitScope();
- }
-
// Generate the error and stacktrace strings for the error message.
String& exc_str = String::Handle(T->zone());
String& stacktrace_str = String::Handle(T->zone());
@@ -766,7 +758,6 @@
simulator_(NULL),
mutex_(new Mutex()),
saved_stack_limit_(0),
- stack_base_(0),
stack_overflow_flags_(0),
stack_overflow_count_(0),
message_handler_(NULL),
@@ -798,7 +789,9 @@
field_invalidation_gen_(kInvalidGen),
prefix_invalidation_gen_(kInvalidGen) {
flags_.CopyFrom(api_flags);
- Thread::Current()->set_vm_tag(VMTag::kEmbedderTagId);
+ // TODO(asiva): A Thread is not available here, need to figure out
+ // how the vm_tag (kEmbedderTagId) can be set, these tags need to
+ // move to the OSThread structure.
set_user_tag(UserTags::kDefaultUserTag);
}
@@ -987,19 +980,7 @@
}
-// TODO(5411455): Use flag to override default value and Validate the
-// stack size by querying OS.
-uword Isolate::GetSpecifiedStackSize() {
- ASSERT(Isolate::kStackSizeBuffer < OSThread::GetMaxStackSize());
- uword stack_size = OSThread::GetMaxStackSize() - Isolate::kStackSizeBuffer;
- return stack_size;
-}
-
-
void Isolate::SetStackLimitFromStackBase(uword stack_base) {
- // Set stack base.
- stack_base_ = stack_base;
-
// Set stack limit.
#if defined(USING_SIMULATOR)
// Ignore passed-in native stack top and use Simulator stack top.
@@ -1008,7 +989,7 @@
stack_base = sim->StackTop();
// The overflow area is accounted for by the simulator.
#endif
- SetStackLimit(stack_base - GetSpecifiedStackSize());
+ SetStackLimit(stack_base - OSThread::GetSpecifiedStackSize());
}
@@ -1026,19 +1007,6 @@
void Isolate::ClearStackLimit() {
SetStackLimit(~static_cast<uword>(0));
- stack_base_ = 0;
-}
-
-
-bool Isolate::GetProfilerStackBounds(uword* lower, uword* upper) const {
- uword stack_upper = stack_base_;
- if (stack_upper == 0) {
- return false;
- }
- uword stack_lower = stack_upper - GetSpecifiedStackSize();
- *lower = stack_lower;
- *upper = stack_upper;
- return true;
}
@@ -1322,7 +1290,6 @@
static MessageHandler::MessageStatus RunIsolate(uword parameter) {
Isolate* isolate = reinterpret_cast<Isolate*>(parameter);
IsolateSpawnState* state = NULL;
- Thread* thread = Thread::Current();
{
// TODO(turnidge): Is this locking required here at all anymore?
MutexLocker ml(isolate->mutex());
@@ -1330,6 +1297,7 @@
}
{
StartIsolateScope start_scope(isolate);
+ Thread* thread = Thread::Current();
ASSERT(thread->isolate() == isolate);
StackZone zone(thread);
HandleScope handle_scope(thread);
@@ -1432,8 +1400,8 @@
{
// Print the error if there is one. This may execute dart code to
// print the exception object, so we need to use a StartIsolateScope.
- Thread* thread = Thread::Current();
StartIsolateScope start_scope(isolate);
+ Thread* thread = Thread::Current();
ASSERT(thread->isolate() == isolate);
StackZone zone(thread);
HandleScope handle_scope(thread);
@@ -1505,18 +1473,6 @@
}
-static int MostUsedFunctionFirst(const Function* const* a,
- const Function* const* b) {
- if ((*a)->usage_counter() > (*b)->usage_counter()) {
- return -1;
- } else if ((*a)->usage_counter() < (*b)->usage_counter()) {
- return 1;
- } else {
- return 0;
- }
-}
-
-
void Isolate::AddClosureFunction(const Function& function) const {
GrowableObjectArray& closures =
GrowableObjectArray::Handle(object_store()->closure_functions());
@@ -1573,47 +1529,6 @@
}
-static void AddFunctionsFromClass(const Class& cls,
- GrowableArray<const Function*>* functions) {
- const Array& class_functions = Array::Handle(cls.functions());
- // Class 'dynamic' is allocated/initialized in a special way, leaving
- // the functions field NULL instead of empty.
- const int func_len = class_functions.IsNull() ? 0 : class_functions.Length();
- for (int j = 0; j < func_len; j++) {
- Function& function = Function::Handle();
- function ^= class_functions.At(j);
- if (function.usage_counter() > 0) {
- functions->Add(&function);
- }
- }
-}
-
-
-void Isolate::PrintInvokedFunctions() {
- ASSERT(this == Isolate::Current());
- const GrowableObjectArray& libraries =
- GrowableObjectArray::Handle(object_store()->libraries());
- Library& library = Library::Handle();
- GrowableArray<const Function*> invoked_functions;
- for (int i = 0; i < libraries.Length(); i++) {
- library ^= libraries.At(i);
- Class& cls = Class::Handle();
- ClassDictionaryIterator iter(library,
- ClassDictionaryIterator::kIteratePrivate);
- while (iter.HasNext()) {
- cls = iter.GetNextClass();
- AddFunctionsFromClass(cls, &invoked_functions);
- }
- }
- invoked_functions.Sort(MostUsedFunctionFirst);
- for (int i = 0; i < invoked_functions.length(); i++) {
- OS::Print("%10" Pd " x %s\n",
- invoked_functions[i]->usage_counter(),
- invoked_functions[i]->ToFullyQualifiedCString());
- }
-}
-
-
class FinalizeWeakPersistentHandlesVisitor : public HandleVisitor {
public:
FinalizeWeakPersistentHandlesVisitor() : HandleVisitor(Thread::Current()) {
@@ -1670,7 +1585,6 @@
// Finalize any weak persistent handles with a non-null referent.
FinalizeWeakPersistentHandlesVisitor visitor;
api_state()->weak_persistent_handles().VisitHandles(&visitor);
- api_state()->prologue_weak_persistent_handles().VisitHandles(&visitor);
if (FLAG_trace_isolates) {
heap()->PrintSizes();
@@ -1695,7 +1609,9 @@
void Isolate::Shutdown() {
ASSERT(this == Isolate::Current());
// Wait until all background compilation has finished.
- BackgroundCompiler::Stop(background_compiler_);
+ if (background_compiler_ != NULL) {
+ BackgroundCompiler::Stop(background_compiler_);
+ }
#if defined(DEBUG)
if (heap_ != NULL) {
@@ -1758,15 +1674,10 @@
// TODO(5411455): For now just make sure there are no current isolates
// as we are shutting down the isolate.
Thread::ExitIsolate();
- // All threads should have exited by now.
- thread_registry()->CheckNotScheduled(this);
}
Dart_IsolateCreateCallback Isolate::create_callback_ = NULL;
-Dart_IsolateInterruptCallback Isolate::interrupt_callback_ = NULL;
-Dart_IsolateUnhandledExceptionCallback
- Isolate::unhandled_exception_callback_ = NULL;
Dart_IsolateShutdownCallback Isolate::shutdown_callback_ = NULL;
Dart_FileOpenCallback Isolate::file_open_callback_ = NULL;
Dart_FileReadCallback Isolate::file_read_callback_ = NULL;
@@ -1779,15 +1690,13 @@
bool Isolate::creation_enabled_ = false;
void Isolate::IterateObjectPointers(ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_handles,
bool validate_frames) {
HeapIterationScope heap_iteration_scope;
- VisitObjectPointers(visitor, visit_prologue_weak_handles, validate_frames);
+ VisitObjectPointers(visitor, validate_frames);
}
void Isolate::VisitObjectPointers(ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_handles,
bool validate_frames) {
ASSERT(visitor != NULL);
@@ -1802,7 +1711,7 @@
// Visit the dart api state for all local and persistent handles.
if (api_state() != NULL) {
- api_state()->VisitObjectPointers(visitor, visit_prologue_weak_handles);
+ api_state()->VisitObjectPointers(visitor);
}
// Visit the current tag which is stored in the isolate.
@@ -1843,17 +1752,9 @@
}
-void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor,
- bool visit_prologue_weak_handles) {
+void Isolate::VisitWeakPersistentHandles(HandleVisitor* visitor) {
if (api_state() != NULL) {
- api_state()->VisitWeakHandles(visitor, visit_prologue_weak_handles);
- }
-}
-
-
-void Isolate::VisitPrologueWeakPersistentHandles(HandleVisitor* visitor) {
- if (api_state() != NULL) {
- api_state()->VisitPrologueWeakHandles(visitor);
+ api_state()->VisitWeakHandles(visitor);
}
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 547ce08..95068b7 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -121,13 +121,10 @@
// Visit all object pointers.
void IterateObjectPointers(ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles,
bool validate_frames);
// Visits weak object pointers.
- void VisitWeakPersistentHandles(HandleVisitor* visitor,
- bool visit_prologue_weak_persistent_handles);
- void VisitPrologueWeakPersistentHandles(HandleVisitor* visitor);
+ void VisitWeakPersistentHandles(HandleVisitor* visitor);
StoreBuffer* store_buffer() { return store_buffer_; }
@@ -254,8 +251,6 @@
// The true stack limit for this isolate.
uword saved_stack_limit() const { return saved_stack_limit_; }
- uword stack_base() const { return stack_base_; }
-
// Stack overflow flags
enum {
kOsrRequest = 0x1, // Current stack overflow caused by OSR request.
@@ -274,13 +269,6 @@
// stack overflow is called.
uword GetAndClearStackOverflowFlags();
- // Retrieve the stack address bounds for profiler.
- bool GetProfilerStackBounds(uword* lower, uword* upper) const;
-
- static uword GetSpecifiedStackSize();
-
- static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize);
-
// Interrupt bits.
enum {
kVMInterrupt = 0x1, // Internal VM checks: safepoints, store buffers, etc.
@@ -442,21 +430,6 @@
return create_callback_;
}
- static void SetInterruptCallback(Dart_IsolateInterruptCallback cb) {
- interrupt_callback_ = cb;
- }
- static Dart_IsolateInterruptCallback InterruptCallback() {
- return interrupt_callback_;
- }
-
- static void SetUnhandledExceptionCallback(
- Dart_IsolateUnhandledExceptionCallback cb) {
- unhandled_exception_callback_ = cb;
- }
- static Dart_IsolateUnhandledExceptionCallback UnhandledExceptionCallback() {
- return unhandled_exception_callback_;
- }
-
static void SetShutdownCallback(Dart_IsolateShutdownCallback cb) {
shutdown_callback_ = cb;
}
@@ -697,15 +670,12 @@
void Shutdown();
void BuildName(const char* name_prefix);
- void PrintInvokedFunctions();
void ProfileIdle();
// Visit all object pointers. Caller must ensure concurrent sweeper is not
// running, and the visitor must not allocate.
- void VisitObjectPointers(ObjectPointerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles,
- bool validate_frames);
+ void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
void set_user_tag(uword tag) {
user_tag_ = tag;
@@ -742,6 +712,8 @@
}
// Accessed from generated code:
+ // TODO(asiva): Need to consider moving the stack_limit_ from isolate to
+ // being thread specific.
uword stack_limit_;
StoreBuffer* store_buffer_;
Heap* heap_;
@@ -777,7 +749,6 @@
Simulator* simulator_;
Mutex* mutex_; // protects stack_limit_, saved_stack_limit_, compiler stats.
uword saved_stack_limit_;
- uword stack_base_;
uword stack_overflow_flags_;
int32_t stack_overflow_count_;
MessageHandler* message_handler_;
@@ -863,8 +834,6 @@
#undef ISOLATE_TIMELINE_STREAM_VARIABLE
static Dart_IsolateCreateCallback create_callback_;
- static Dart_IsolateInterruptCallback interrupt_callback_;
- static Dart_IsolateUnhandledExceptionCallback unhandled_exception_callback_;
static Dart_IsolateShutdownCallback shutdown_callback_;
static Dart_FileOpenCallback file_open_callback_;
static Dart_FileReadCallback file_read_callback_;
@@ -914,7 +883,7 @@
if (saved_isolate_ != new_isolate_) {
ASSERT(Isolate::Current() == NULL);
// Ensure this is not a nested 'isolate enter' with prior state.
- ASSERT(new_isolate_->stack_base() == 0);
+ ASSERT(new_isolate_->saved_stack_limit() == 0);
Thread::EnterIsolate(new_isolate_);
}
}
@@ -928,7 +897,7 @@
if (saved_isolate_ != new_isolate_) {
ASSERT(saved_isolate_ == NULL);
// ASSERT that we have bottomed out of all Dart invocations.
- ASSERT(new_isolate_->stack_base() == 0);
+ ASSERT(new_isolate_->saved_stack_limit() == 0);
Thread::ExitIsolate();
}
}
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 318702c..92cbc4e 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -6,7 +6,7 @@
#define VM_JSON_STREAM_H_
#include "include/dart_api.h" // for Dart_Port
-#include "platform/json.h"
+#include "platform/text_buffer.h"
#include "vm/allocation.h"
#include "vm/service.h"
diff --git a/runtime/vm/json_test.cc b/runtime/vm/json_test.cc
index 6ca6760..245bdd6 100644
--- a/runtime/vm/json_test.cc
+++ b/runtime/vm/json_test.cc
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "platform/assert.h"
-#include "platform/json.h"
+#include "platform/text_buffer.h"
#include "vm/json_stream.h"
#include "vm/unit_test.h"
#include "vm/dart_api_impl.h"
@@ -11,131 +11,12 @@
namespace dart {
-TEST_CASE(JSON_ScanJSON) {
- const char* msg = "{ \"id\": 5, \"command\" : \"Debugger.pause\" }";
-
- JSONScanner scanner(msg);
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenIllegal);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenLBrace);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
- EXPECT(scanner.IsStringLiteral("id"));
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenInteger);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenComma);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
- EXPECT(scanner.IsStringLiteral("command"));
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenColon);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenString);
- EXPECT(scanner.IsStringLiteral("Debugger.pause"));
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenRBrace);
- scanner.Scan();
- EXPECT_EQ(scanner.CurrentToken(), JSONScanner::TokenEOM);
-}
-
-
-TEST_CASE(JSON_SyntaxError) {
- const char* jobj = "{ \"id\": 5, "
- " \"command\" : \"Debugger.stop\"" // Missing comma.
- " \"params\" : { "
- " \"url\" : \"blah.dart\", " // Missing comma.
- " \"line\": 111, "
- " },"
- " \"foo\": \"outer foo\", "
- "}";
- JSONReader reader(jobj);
- bool found;
-
- found = reader.Seek("id");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kInteger);
- found = reader.Seek("params");
- EXPECT(!found);
- EXPECT(reader.Error());
- EXPECT_EQ(reader.Type(), JSONReader::kNone);
- EXPECT_EQ(0, reader.ValueLen());
- EXPECT(reader.ValueChars() == NULL);
-}
-
-
-TEST_CASE(JSON_JSONReader) {
- const char* jobj = "{ \"id\": 5, "
- " \"command\" : \"Debugger.setBreakpoint\","
- " \"params\" : { "
- " \"url\" : \"blah.dart\", "
- " \"foo\" : [null, 1, { }, \"bar\", true, false],"
- " \"line\": 111, "
- " },"
- " \"foo\": \"outer foo\", "
- " \"quote\": \"\\\"\", "
- " \"white\": \"\\t \\n\", "
- "}";
-
- JSONReader reader(jobj);
- bool found;
- char s[128];
-
- found = reader.Seek("id");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kInteger);
- found = reader.Seek("foo");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kString);
- EXPECT(reader.IsStringLiteral("outer foo"));
-
- found = reader.Seek("quote");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kString);
- reader.GetRawValueChars(s, sizeof s);
- EXPECT_STREQ("\\\"", s);
- reader.GetDecodedValueChars(s, sizeof s);
- EXPECT_STREQ("\"", s);
-
- found = reader.Seek("white");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kString);
- reader.GetRawValueChars(s, sizeof s);
- EXPECT_STREQ("\\t \\n", s);
- reader.GetDecodedValueChars(s, sizeof s);
- EXPECT_STREQ("\t \n", s);
-
- found = reader.Seek("line");
- EXPECT(!found);
- found = reader.Seek("params");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kObject);
- reader.Set(reader.ValueChars());
- found = reader.Seek("foo");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kArray);
- found = reader.Seek("non-existing");
- EXPECT(!found);
- found = reader.Seek("line");
- EXPECT(found);
- EXPECT_EQ(reader.Type(), JSONReader::kInteger);
-}
-
-
TEST_CASE(JSON_TextBuffer) {
TextBuffer w(5); // Small enough to make buffer grow at least once.
w.Printf("{ \"%s\" : %d", "length", 175);
EXPECT_STREQ("{ \"length\" : 175", w.buf());
w.Printf(", \"%s\" : \"%s\" }", "command", "stopIt");
EXPECT_STREQ("{ \"length\" : 175, \"command\" : \"stopIt\" }", w.buf());
-
- JSONReader r(w.buf());
- bool found = r.Seek("command");
- EXPECT(found);
- EXPECT_EQ(r.Type(), JSONReader::kString);
- EXPECT(r.IsStringLiteral("stopIt"));
}
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index e460a2d..de4f773 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -6,8 +6,6 @@
#include "vm/assembler.h"
#include "vm/il_printer.h"
-#include "vm/intermediate_language.h"
-#include "vm/flow_graph_compiler.h"
#include "vm/log.h"
#include "vm/stack_frame.h"
diff --git a/runtime/vm/log.cc b/runtime/vm/log.cc
index e29432f..d576beb 100644
--- a/runtime/vm/log.cc
+++ b/runtime/vm/log.cc
@@ -32,7 +32,9 @@
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
if (isolate != NULL && Log::ShouldLogForIsolate(isolate)) {
- return thread->log();
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ return os_thread->log();
} else {
return Log::NoOpLog();
}
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index ae7edab..314eb7c 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -399,7 +399,7 @@
info.handler = &handler;
info.ports = ports;
info.count = 10;
- OSThread::Start(SendMessages, reinterpret_cast<uword>(&info));
+ OSThread::Start("SendMessages", SendMessages, reinterpret_cast<uword>(&info));
while (sleep < kMaxSleep && handler.message_count() < 11) {
OS::Sleep(10);
sleep += 10;
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index 13b896c..4d0a348 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -30,7 +30,7 @@
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
if (obj.IsType()) {
const Class& cls = Class::Handle(Type::Cast(obj).type_class());
- return Api::NewHandle(I, cls.UserVisibleName());
+ return Api::NewHandle(T, cls.UserVisibleName());
} else {
RETURN_TYPE_ERROR(Z, object, Class/Type);
}
@@ -48,7 +48,7 @@
RETURN_NULL_ERROR(str);
}
CHECK_CALLBACK_STATE(T);
- return Api::NewHandle(I, String::New(str));
+ return Api::NewHandle(T, String::New(str));
} else {
RETURN_TYPE_ERROR(Z, object, Class/Type);
}
@@ -85,7 +85,7 @@
const Class& cls = Class::Handle(Z, Type::Cast(obj).type_class());
const Error& error = Error::Handle(Z, cls.EnsureIsFinalized(T));
if (!error.IsNull()) {
- return Api::NewHandle(I, error.raw());
+ return Api::NewHandle(T, error.raw());
}
const Array& func_array = Array::Handle(Z, cls.functions());
@@ -124,7 +124,7 @@
"%s expects argument 'target' to be a class or library.",
CURRENT_FUNC);
}
- return Api::NewHandle(I, Array::MakeArray(names));
+ return Api::NewHandle(T, Array::MakeArray(names));
}
@@ -205,7 +205,7 @@
func_kind == RawFunction::kConstructor);
}
#endif
- return Api::NewHandle(I, func.raw());
+ return Api::NewHandle(T, func.raw());
}
@@ -215,7 +215,7 @@
if (func.IsNull()) {
RETURN_TYPE_ERROR(Z, function, Function);
}
- return Api::NewHandle(I, func.UserVisibleName());
+ return Api::NewHandle(T, func.UserVisibleName());
}
@@ -227,7 +227,7 @@
}
if (func.IsNonImplicitClosureFunction()) {
RawFunction* parent_function = func.parent_function();
- return Api::NewHandle(I, parent_function);
+ return Api::NewHandle(T, parent_function);
}
const Class& owner = Class::Handle(Z, func.Owner());
ASSERT(!owner.IsNull());
@@ -240,9 +240,9 @@
ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
}
#endif
- return Api::NewHandle(I, owner.library());
+ return Api::NewHandle(T, owner.library());
} else {
- return Api::NewHandle(I, owner.RareType());
+ return Api::NewHandle(T, owner.RareType());
}
}
@@ -317,7 +317,7 @@
}
const String& name = String::Handle(Z, lib.name());
ASSERT(!name.IsNull());
- return Api::NewHandle(I, name.raw());
+ return Api::NewHandle(T, name.raw());
}
DART_EXPORT Dart_Handle Dart_LibraryGetClassNames(Dart_Handle library) {
@@ -347,7 +347,7 @@
names.Add(name);
}
}
- return Api::NewHandle(I, Array::MakeArray(names));
+ return Api::NewHandle(T, Array::MakeArray(names));
}
@@ -363,7 +363,7 @@
ASSERT(ClassFinalizer::AllClassesFinalized());
RawFunction* rf = Closure::function(closure_obj);
- return Api::NewHandle(I, rf);
+ return Api::NewHandle(T, rf);
}
} // namespace dart
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index 9395bf3..c707c9e 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -22,6 +22,27 @@
}
+class IsolateSaver {
+ public:
+ explicit IsolateSaver(Isolate* current_isolate)
+ : saved_isolate_(current_isolate) {
+ if (current_isolate != NULL) {
+ ASSERT(current_isolate == Isolate::Current());
+ Thread::ExitIsolate();
+ }
+ }
+ ~IsolateSaver() {
+ if (saved_isolate_ != NULL) {
+ Thread::EnterIsolate(saved_isolate_);
+ }
+ }
+ private:
+ Isolate* saved_isolate_;
+
+ DISALLOW_COPY_AND_ASSIGN(IsolateSaver);
+};
+
+
DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) {
uint8_t* buffer = NULL;
ApiMessageWriter writer(&buffer, allocator);
@@ -48,7 +69,6 @@
}
// Start the native port without a current isolate.
IsolateSaver saver(Isolate::Current());
- Thread::ExitIsolate();
NativeMessageHandler* nmh = new NativeMessageHandler(name, handler);
Dart_Port port_id = PortMap::CreatePort(nmh);
@@ -60,7 +80,6 @@
DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) {
// Close the native port without a current isolate.
IsolateSaver saver(Isolate::Current());
- Thread::ExitIsolate();
// TODO(turnidge): Check that the port is native before trying to close.
return PortMap::ClosePort(native_port_id);
@@ -75,14 +94,14 @@
if (error.IsNull()) {
*result = Api::Success();
} else {
- *result = Api::NewHandle(thread->isolate(), error.raw());
+ *result = Api::NewHandle(thread, error.raw());
}
}
DART_EXPORT Dart_Handle Dart_CompileAll() {
DARTSCOPE(Thread::Current());
- Dart_Handle result = Api::CheckAndFinalizePendingClasses(I);
+ Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
if (::Dart_IsError(result)) {
return result;
}
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index adedfb7..92a99e8 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -36,7 +36,7 @@
Dart_EnterScope(); // Enter a new Dart API scope as we invoke API entries.
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
Dart_NativeFunction native_function =
- resolver(Api::NewHandle(Isolate::Current(), function_name.raw()),
+ resolver(Api::NewHandle(Thread::Current(), function_name.raw()),
number_of_arguments, auto_setup_scope);
Dart_ExitScope(); // Exit the Dart API scope.
return reinterpret_cast<NativeFunction>(native_function);
@@ -98,8 +98,8 @@
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- ApiLocalScope* current_top_scope = state->top_scope();
- ApiLocalScope* scope = state->reusable_scope();
+ ApiLocalScope* current_top_scope = thread->api_top_scope();
+ ApiLocalScope* scope = thread->api_reusable_scope();
TRACE_NATIVE_CALL("0x%" Px "", reinterpret_cast<uintptr_t>(func));
if (scope == NULL) {
scope = new ApiLocalScope(current_top_scope,
@@ -109,19 +109,19 @@
scope->Reinit(thread,
current_top_scope,
thread->top_exit_frame_info());
- state->set_reusable_scope(NULL);
+ thread->set_api_reusable_scope(NULL);
}
- state->set_top_scope(scope); // New scope is now the top scope.
+ thread->set_api_top_scope(scope); // New scope is now the top scope.
func(args);
ASSERT(current_top_scope == scope->previous());
- state->set_top_scope(current_top_scope); // Reset top scope to previous.
- if (state->reusable_scope() == NULL) {
+ thread->set_api_top_scope(current_top_scope); // Reset top scope to previous.
+ if (thread->api_reusable_scope() == NULL) {
scope->Reset(thread); // Reset the old scope which we just exited.
- state->set_reusable_scope(scope);
+ thread->set_api_reusable_scope(scope);
} else {
- ASSERT(state->reusable_scope() != scope);
+ ASSERT(thread->api_reusable_scope() != scope);
delete scope;
}
DEOPTIMIZE_ALOT;
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2e4bf4a..169b42e 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -74,9 +74,9 @@
DECLARE_FLAG(bool, write_protect_code);
-static const char* kGetterPrefix = "get:";
+static const char* const kGetterPrefix = "get:";
static const intptr_t kGetterPrefixLength = strlen(kGetterPrefix);
-static const char* kSetterPrefix = "set:";
+static const char* const kSetterPrefix = "set:";
static const intptr_t kSetterPrefixLength = strlen(kSetterPrefix);
// A cache of VM heap allocated preinitialized empty ic data entry arrays.
@@ -2218,29 +2218,6 @@
}
-intptr_t Class::FindFunctionIndex(const Function& needle) const {
- Thread* thread = Thread::Current();
- if (EnsureIsFinalized(thread) != Error::null()) {
- return -1;
- }
- REUSABLE_ARRAY_HANDLESCOPE(thread);
- REUSABLE_FUNCTION_HANDLESCOPE(thread);
- Array& funcs = thread->ArrayHandle();
- Function& function = thread->FunctionHandle();
- funcs ^= functions();
- ASSERT(!funcs.IsNull());
- const intptr_t len = funcs.Length();
- for (intptr_t i = 0; i < len; i++) {
- function ^= funcs.At(i);
- if (function.raw() == needle.raw()) {
- return i;
- }
- }
- // No function found.
- return -1;
-}
-
-
RawFunction* Class::FunctionFromIndex(intptr_t idx) const {
const Array& funcs = Array::Handle(functions());
if ((idx < 0) || (idx >= funcs.Length())) {
@@ -2868,8 +2845,8 @@
// Shared handles used during the iteration.
String& member_name = String::Handle();
- const PatchClass& patch_class =
- PatchClass::Handle(PatchClass::New(*this, patch));
+ const PatchClass& patch_class = PatchClass::Handle(
+ PatchClass::New(*this, Script::Handle(patch.script())));
Array& orig_list = Array::Handle(functions());
intptr_t orig_len = orig_list.Length();
@@ -2971,8 +2948,10 @@
SetFields(new_list);
// The functions and fields in the patch class are no longer needed.
+ // The patch class itself is also no longer needed.
patch.SetFunctions(Object::empty_array());
patch.SetFields(Object::empty_array());
+ Library::Handle(patch.library()).RemovePatchClass(patch);
return true;
}
@@ -3097,46 +3076,6 @@
}
-intptr_t Class::FindFieldIndex(const Field& needle) const {
- Thread* thread = Thread::Current();
- if (EnsureIsFinalized(thread) != Error::null()) {
- return -1;
- }
- REUSABLE_ARRAY_HANDLESCOPE(thread);
- REUSABLE_FIELD_HANDLESCOPE(thread);
- REUSABLE_STRING_HANDLESCOPE(thread);
- Array& fields_array = thread->ArrayHandle();
- Field& field = thread->FieldHandle();
- String& field_name = thread->StringHandle();
- fields_array ^= fields();
- ASSERT(!fields_array.IsNull());
- String& needle_name = String::Handle(thread->zone());
- needle_name ^= needle.name();
- const intptr_t len = fields_array.Length();
- for (intptr_t i = 0; i < len; i++) {
- field ^= fields_array.At(i);
- field_name ^= field.name();
- if (field_name.Equals(needle_name)) {
- return i;
- }
- }
- // No field found.
- return -1;
-}
-
-
-RawField* Class::FieldFromIndex(intptr_t idx) const {
- const Array& flds = Array::Handle(fields());
- if ((idx < 0) || (idx >= flds.Length())) {
- return Field::null();
- }
- Field& field = Field::Handle();
- field ^= flds.At(idx);
- ASSERT(!field.IsNull());
- return field.raw();
-}
-
-
template <class FakeInstance>
RawClass* Class::New(intptr_t index) {
ASSERT(Object::class_class() != Class::null());
@@ -3600,6 +3539,14 @@
}
+void Class::ResetFinalization() const {
+ ASSERT(IsTopLevel());
+ set_state_bits(ClassFinalizedBits::update(RawClass::kAllocated,
+ raw_ptr()->state_bits_));
+ set_state_bits(TypeFinalizedBit::update(false, raw_ptr()->state_bits_));
+}
+
+
void Class::set_is_prefinalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kPreFinalized,
@@ -3634,25 +3581,9 @@
}
-void Class::SetPatchClass(const Class& cls) const {
- ASSERT(GetPatchClass() == Class::null());
- const GrowableObjectArray& patch_classes =
- GrowableObjectArray::Handle(Library::Handle(library()).patch_classes());
- patch_classes.Add(cls);
-}
-
-
RawClass* Class::GetPatchClass() const {
- const GrowableObjectArray& patch_classes =
- GrowableObjectArray::Handle(Library::Handle(library()).patch_classes());
- Class& pc = Class::Handle();
- for (intptr_t i = 0; i < patch_classes.Length(); i++) {
- pc ^= patch_classes.At(i);
- if (pc.Name() == this->Name()) { // Names are canonicalized.
- return pc.raw();
- }
- }
- return Class::null();
+ const Library& lib = Library::Handle(library());
+ return lib.GetPatchClass(String::Handle(Name()));
}
@@ -5252,10 +5183,21 @@
RawPatchClass* PatchClass::New(const Class& patched_class,
- const Class& source_class) {
+ const Class& origin_class) {
const PatchClass& result = PatchClass::Handle(PatchClass::New());
result.set_patched_class(patched_class);
- result.set_source_class(source_class);
+ result.set_origin_class(origin_class);
+ result.set_script(Script::Handle(origin_class.script()));
+ return result.raw();
+}
+
+
+RawPatchClass* PatchClass::New(const Class& patched_class,
+ const Script& script) {
+ const PatchClass& result = PatchClass::Handle(PatchClass::New());
+ result.set_patched_class(patched_class);
+ result.set_origin_class(patched_class);
+ result.set_script(script);
return result.raw();
}
@@ -5269,19 +5211,18 @@
}
-RawScript* PatchClass::Script() const {
- const Class& source_class = Class::Handle(this->source_class());
- return source_class.script();
-}
-
-
void PatchClass::set_patched_class(const Class& value) const {
StorePointer(&raw_ptr()->patched_class_, value.raw());
}
-void PatchClass::set_source_class(const Class& value) const {
- StorePointer(&raw_ptr()->source_class_, value.raw());
+void PatchClass::set_origin_class(const Class& value) const {
+ StorePointer(&raw_ptr()->origin_class_, value.raw());
+}
+
+
+void PatchClass::set_script(const Script& value) const {
+ StorePointer(&raw_ptr()->script_, value.raw());
}
@@ -6880,7 +6821,7 @@
return Class::Cast(obj).raw();
}
ASSERT(obj.IsPatchClass());
- return PatchClass::Cast(obj).source_class();
+ return PatchClass::Cast(obj).origin_class();
}
@@ -6901,7 +6842,7 @@
return Class::Cast(obj).script();
}
ASSERT(obj.IsPatchClass());
- return PatchClass::Cast(obj).Script();
+ return PatchClass::Cast(obj).script();
}
@@ -7453,7 +7394,17 @@
return Class::Cast(obj).raw();
}
ASSERT(obj.IsPatchClass());
- return PatchClass::Cast(obj).source_class();
+ return PatchClass::Cast(obj).origin_class();
+}
+
+
+RawScript* Field::script() const {
+ const Object& obj = Object::Handle(raw_ptr()->owner_);
+ if (obj.IsClass()) {
+ return Class::Cast(obj).script();
+ }
+ ASSERT(obj.IsPatchClass());
+ return PatchClass::Cast(obj).script();
}
@@ -7513,6 +7464,35 @@
}
+RawField* Field::NewTopLevel(const String& name,
+ bool is_final,
+ bool is_const,
+ const Object& owner,
+ intptr_t token_pos) {
+ ASSERT(!owner.IsNull());
+ const Field& result = Field::Handle(Field::New());
+ result.set_name(name);
+ result.set_is_static(true);
+ result.set_is_final(is_final);
+ result.set_is_const(is_const);
+ result.set_is_reflectable(true);
+ result.set_is_double_initialized(false);
+ result.set_owner(owner);
+ result.set_token_pos(token_pos);
+ result.set_has_initializer(false);
+ result.set_is_unboxing_candidate(true);
+ result.set_guarded_cid(FLAG_use_field_guards ? kIllegalCid : kDynamicCid);
+ result.set_is_nullable(FLAG_use_field_guards ? false : true);
+ result.set_guarded_list_length_in_object_offset(Field::kUnknownLengthOffset);
+ // Presently, we only attempt to remember the list length for final fields.
+ if (is_final && FLAG_use_field_guards) {
+ result.set_guarded_list_length(Field::kUnknownFixedLength);
+ } else {
+ result.set_guarded_list_length(Field::kNoFixedLength);
+ }
+ return result.raw();
+}
+
RawField* Field::Clone(const Class& new_owner) const {
Field& clone = Field::Handle();
@@ -7584,14 +7564,16 @@
"Field <%s.%s>:%s%s%s", cls_name, field_name, kF0, kF1, kF2);
}
+
void Field::PrintJSONImpl(JSONStream* stream, bool ref) const {
JSONObject jsobj(stream);
Class& cls = Class::Handle(owner());
- intptr_t id = cls.FindFieldIndex(*this);
- ASSERT(id >= 0);
- intptr_t cid = cls.id();
+ String& field_name = String::Handle(name());
+ field_name = String::EncodeIRI(field_name);
AddCommonObjectProperties(&jsobj, "Field", ref);
- jsobj.AddFixedServiceId("classes/%" Pd "/fields/%" Pd "", cid, id);
+ jsobj.AddFixedServiceId("classes/%" Pd "/fields/%s",
+ cls.id(), field_name.ToCString());
+
const String& user_name = String::Handle(PrettyName());
const String& vm_name = String::Handle(name());
AddNameProperties(&jsobj, user_name, vm_name);
@@ -8994,6 +8976,10 @@
intptr_t to_line,
intptr_t to_column) const {
const String& src = String::Handle(Source());
+ if (src.IsNull()) {
+ ASSERT(Dart::IsRunningPrecompiledCode());
+ return Symbols::OptimizedOut().raw();
+ }
intptr_t length = src.Length();
intptr_t line = 1 + line_offset();
intptr_t column = 1;
@@ -9179,11 +9165,10 @@
ClassDictionaryIterator::ClassDictionaryIterator(const Library& library,
IterationKind kind)
: DictionaryIterator(library),
- anon_array_((kind == kIteratePrivate) ?
- Array::Handle(library.anonymous_classes()) : Object::empty_array()),
- anon_size_((kind == kIteratePrivate) ?
- library.num_anonymous_classes() : 0),
- anon_ix_(0) {
+ toplevel_class_(Class::Handle(
+ (kind == kIteratePrivate)
+ ? library.toplevel_class()
+ : Class::null())) {
MoveToNextClass();
}
@@ -9197,8 +9182,9 @@
MoveToNextClass();
return cls.raw();
}
- ASSERT(anon_ix_ < anon_size_);
- cls ^= anon_array_.At(anon_ix_++);
+ ASSERT(!toplevel_class_.IsNull());
+ cls = toplevel_class_.raw();
+ toplevel_class_ = Class::null();
return cls.raw();
}
@@ -9345,6 +9331,52 @@
}
+void Library::AddPatchClass(const Class& cls) const {
+ ASSERT(cls.is_patch());
+ ASSERT(GetPatchClass(String::Handle(cls.Name())) == Class::null());
+ const GrowableObjectArray& patch_classes =
+ GrowableObjectArray::Handle(this->patch_classes());
+ patch_classes.Add(cls);
+}
+
+
+RawClass* Library::GetPatchClass(const String& name) const {
+ const GrowableObjectArray& patch_classes =
+ GrowableObjectArray::Handle(this->patch_classes());
+ Object& obj = Object::Handle();
+ for (intptr_t i = 0; i < patch_classes.Length(); i++) {
+ obj = patch_classes.At(i);
+ if (obj.IsClass() &&
+ (Class::Cast(obj).Name() == name.raw())) { // Names are canonicalized.
+ return Class::RawCast(obj.raw());
+ }
+ }
+ return Class::null();
+}
+
+
+void Library::RemovePatchClass(const Class& cls) const {
+ ASSERT(cls.is_patch());
+ const GrowableObjectArray& patch_classes =
+ GrowableObjectArray::Handle(this->patch_classes());
+ const intptr_t num_classes = patch_classes.Length();
+ intptr_t i = 0;
+ while (i < num_classes) {
+ if (cls.raw() == patch_classes.At(i)) break;
+ i++;
+ }
+ if (i == num_classes) return;
+ // Replace the entry with the script. We keep the script so that
+ // Library::LoadedScripts() can find it without having to iterate
+ // over the members of each class.
+ ASSERT(i < num_classes); // We must have found a class.
+ Class& pc = Class::Handle();
+ pc ^= patch_classes.At(i);
+ const Script& patch_script = Script::Handle(pc.script());
+ patch_classes.SetAt(i, patch_script);
+}
+
+
static RawString* MakeClassMetaName(const Class& cls) {
return Symbols::FromConcat(Symbols::At(), String::Handle(cls.Name()));
}
@@ -9383,32 +9415,31 @@
}
-void Library::AddMetadata(const Class& cls,
+void Library::AddMetadata(const Object& owner,
const String& name,
intptr_t token_pos) const {
const String& metaname = String::Handle(Symbols::New(name));
- Field& field = Field::Handle(Field::New(metaname,
- true, // is_static
- false, // is_final
- false, // is_const
- false, // is_reflectable
- cls,
- Object::dynamic_type(),
- token_pos));
+ const Field& field = Field::Handle(
+ Field::NewTopLevel(metaname,
+ false, // is_final
+ false, // is_const
+ owner,
+ token_pos));
+ field.SetFieldType(Object::dynamic_type());
+ field.set_is_reflectable(false);
field.SetStaticValue(Array::empty_array(), true);
GrowableObjectArray& metadata =
GrowableObjectArray::Handle(this->metadata());
metadata.Add(field, Heap::kOld);
- cls.AddField(field);
}
void Library::AddClassMetadata(const Class& cls,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t token_pos) const {
// We use the toplevel class as the owner of a class's metadata field because
// a class's metadata is in scope of the library, not the class.
- AddMetadata(toplevel_class,
+ AddMetadata(tl_owner,
String::Handle(MakeClassMetaName(cls)),
token_pos);
}
@@ -9416,7 +9447,7 @@
void Library::AddFieldMetadata(const Field& field,
intptr_t token_pos) const {
- AddMetadata(Class::Handle(field.origin()),
+ AddMetadata(Object::Handle(field.RawOwner()),
String::Handle(MakeFieldMetaName(field)),
token_pos);
}
@@ -9424,7 +9455,7 @@
void Library::AddFunctionMetadata(const Function& func,
intptr_t token_pos) const {
- AddMetadata(Class::Handle(func.origin()),
+ AddMetadata(Object::Handle(func.RawOwner()),
String::Handle(MakeFunctionMetaName(func)),
token_pos);
}
@@ -9438,8 +9469,9 @@
}
-void Library::AddLibraryMetadata(const Class& cls, intptr_t token_pos) const {
- AddMetadata(cls, Symbols::TopLevel(), token_pos);
+void Library::AddLibraryMetadata(const Object& tl_owner,
+ intptr_t token_pos) const {
+ AddMetadata(tl_owner, Symbols::TopLevel(), token_pos);
}
@@ -9491,8 +9523,7 @@
Object& metadata = Object::Handle();
metadata = field.StaticValue();
if (field.StaticValue() == Object::empty_array().raw()) {
- metadata = Parser::ParseMetadata(Class::Handle(field.owner()),
- field.token_pos());
+ metadata = Parser::ParseMetadata(field);
if (metadata.IsArray()) {
ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
field.SetStaticValue(Array::Cast(metadata), true);
@@ -9770,8 +9801,7 @@
} else if (entry.IsFunction()) {
owner_script = Function::Cast(entry).script();
} else if (entry.IsField()) {
- cls = Field::Cast(entry).owner();
- owner_script = cls.script();
+ owner_script = Field::Cast(entry).script();
} else {
continue;
}
@@ -9781,27 +9811,31 @@
// Add all scripts from patch classes.
GrowableObjectArray& patches = GrowableObjectArray::Handle(patch_classes());
for (intptr_t i = 0; i < patches.Length(); i++) {
- cls ^= patches.At(i);
- owner_script = cls.script();
+ entry = patches.At(i);
+ if (entry.IsClass()) {
+ owner_script = Class::Cast(entry).script();
+ } else {
+ ASSERT(entry.IsScript());
+ owner_script ^= Script::Cast(entry).raw();
+ }
AddScriptIfUnique(scripts, owner_script);
}
- // Special case: Scripts that only contain external top-level functions are
- // not included above, but can be referenced through a library's anonymous
- // classes. Example: dart-core:identical.dart.
- Array& anon_classes = Array::Handle(anonymous_classes());
- Function& func = Function::Handle();
- Array& functions = Array::Handle();
- for (intptr_t i = 0; i < anon_classes.Length(); i++) {
- cls ^= anon_classes.At(i);
- if (cls.IsNull()) continue;
+ cls ^= toplevel_class();
+ if (!cls.IsNull()) {
owner_script = cls.script();
AddScriptIfUnique(scripts, owner_script);
- functions = cls.functions();
+ // Special case: Scripts that only contain external top-level functions
+ // are not included above, but can be referenced through a library's
+ // anonymous classes. Example: dart-core:identical.dart.
+ Function& func = Function::Handle();
+ Array& functions = Array::Handle(cls.functions());
for (intptr_t j = 0; j < functions.Length(); j++) {
func ^= functions.At(j);
- owner_script = func.script();
- AddScriptIfUnique(scripts, owner_script);
+ if (func.is_external()) {
+ owner_script = func.script();
+ AddScriptIfUnique(scripts, owner_script);
+ }
}
}
@@ -10019,17 +10053,9 @@
}
-void Library::AddAnonymousClass(const Class& cls) const {
- intptr_t num_anonymous = this->raw_ptr()->num_anonymous_;
- Array& anon_array = Array::Handle(this->raw_ptr()->anonymous_classes_);
- if (num_anonymous == anon_array.Length()) {
- intptr_t new_len = (num_anonymous == 0) ? 4 : num_anonymous * 2;
- anon_array = Array::Grow(anon_array, new_len);
- StorePointer(&raw_ptr()->anonymous_classes_, anon_array.raw());
- }
- anon_array.SetAt(num_anonymous, cls);
- num_anonymous++;
- StoreNonPointer(&raw_ptr()->num_anonymous_, num_anonymous);
+void Library::set_toplevel_class(const Class& value) const {
+ ASSERT(raw_ptr()->toplevel_class_ == Class::null());
+ StorePointer(&raw_ptr()->toplevel_class_, value.raw());
}
@@ -10159,12 +10185,10 @@
Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->metadata_,
GrowableObjectArray::New(4, Heap::kOld));
- result.StorePointer(&result.raw_ptr()->anonymous_classes_,
- Object::empty_array().raw());
+ result.StorePointer(&result.raw_ptr()->toplevel_class_, Class::null());
result.StorePointer(&result.raw_ptr()->patch_classes_,
GrowableObjectArray::New(Object::empty_array(),
Heap::kOld));
- result.StoreNonPointer(&result.raw_ptr()->num_anonymous_, 0);
result.StorePointer(&result.raw_ptr()->imports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->exports_, Object::empty_array().raw());
result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
@@ -10219,12 +10243,8 @@
RawObject* Library::Evaluate(const String& expr,
const Array& param_names,
const Array& param_values) const {
- // Take a top-level class and evaluate the expression
- // as a static function of the class.
- Class& top_level_class = Class::Handle();
- Array& top_level_classes = Array::Handle(anonymous_classes());
- ASSERT(top_level_classes.Length() > 0);
- top_level_class ^= top_level_classes.At(0);
+ // Evaluate the expression as a static function of the toplevel class.
+ Class& top_level_class = Class::Handle(toplevel_class());
ASSERT(top_level_class.is_finalized());
return top_level_class.Evaluate(expr, param_names, param_values);
}
@@ -10751,8 +10771,8 @@
const String& lib_url = String::Handle(zone, deferred_lib.url());
Dart_LibraryTagHandler handler = isolate->library_tag_handler();
handler(Dart_kImportTag,
- Api::NewHandle(isolate, importer()),
- Api::NewHandle(isolate, lib_url.raw()));
+ Api::NewHandle(thread, importer()),
+ Api::NewHandle(thread, lib_url.raw()));
} else {
// Another load request is in flight.
ASSERT(deferred_lib.LoadRequested());
@@ -10889,19 +10909,17 @@
}
-void Namespace::AddMetadata(intptr_t token_pos, const Class& owner_class) {
+void Namespace::AddMetadata(const Object& owner, intptr_t token_pos) {
ASSERT(Field::Handle(metadata_field()).IsNull());
- Field& field = Field::Handle(Field::New(Symbols::TopLevel(),
- true, // is_static
+ Field& field = Field::Handle(Field::NewTopLevel(Symbols::TopLevel(),
false, // is_final
false, // is_const
- false, // is_reflectable
- owner_class,
- Object::dynamic_type(),
+ owner,
token_pos));
+ field.set_is_reflectable(false);
+ field.SetFieldType(Object::dynamic_type());
field.SetStaticValue(Array::empty_array(), true);
set_metadata_field(field);
- owner_class.AddField(field);
}
@@ -10914,8 +10932,7 @@
Object& metadata = Object::Handle();
metadata = field.StaticValue();
if (field.StaticValue() == Object::empty_array().raw()) {
- metadata = Parser::ParseMetadata(Class::Handle(field.owner()),
- field.token_pos());
+ metadata = Parser::ParseMetadata(field);
if (metadata.IsArray()) {
ASSERT(Array::Cast(metadata).raw() != Object::empty_array().raw());
field.SetStaticValue(Array::Cast(metadata), true);
@@ -11042,17 +11059,19 @@
RawError* Library::CompileAll() {
- Error& error = Error::Handle();
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ Error& error = Error::Handle(zone);
const GrowableObjectArray& libs = GrowableObjectArray::Handle(
Isolate::Current()->object_store()->libraries());
- Library& lib = Library::Handle();
- Class& cls = Class::Handle();
+ Library& lib = Library::Handle(zone);
+ Class& cls = Class::Handle(zone);
for (int i = 0; i < libs.Length(); i++) {
lib ^= libs.At(i);
ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
while (it.HasNext()) {
cls = it.GetNextClass();
- error = cls.EnsureIsFinalized(Thread::Current());
+ error = cls.EnsureIsFinalized(thread);
if (!error.IsNull()) {
return error.raw();
}
@@ -11062,6 +11081,24 @@
}
}
}
+
+ // Inner functions get added to the closures array. As part of compilation
+ // more closures can be added to the end of the array. Compile all the
+ // closures until we have reached the end of the "worklist".
+ const GrowableObjectArray& closures = GrowableObjectArray::Handle(zone,
+ Isolate::Current()->object_store()->closure_functions());
+ Function& func = Function::Handle(zone);
+ for (int i = 0; i < closures.Length(); i++) {
+ func ^= closures.At(i);
+ if (!func.HasCode()) {
+ error = Compiler::CompileFunction(thread, func);
+ if (!error.IsNull()) {
+ return error.raw();
+ }
+ func.ClearICDataArray();
+ func.ClearCode();
+ }
+ }
return error.raw();
}
@@ -12286,8 +12323,7 @@
const intptr_t len = NumberOfChecks();
for (intptr_t i = 0; i < len; i++) {
GrowableArray<intptr_t> class_ids;
- Function& target = Function::Handle();
- GetCheckAt(i, &class_ids, &target);
+ GetClassIdsAt(i, &class_ids);
bool matches = true;
for (intptr_t k = 0; k < class_ids.length(); k++) {
if (class_ids[k] != cids[k]) {
@@ -12446,6 +12482,19 @@
}
+void ICData::GetClassIdsAt(intptr_t index,
+ GrowableArray<intptr_t>* class_ids) const {
+ ASSERT(index < NumberOfChecks());
+ ASSERT(class_ids != NULL);
+ class_ids->Clear();
+ const Array& data = Array::Handle(ic_data());
+ intptr_t data_pos = index * TestEntryLength();
+ for (intptr_t i = 0; i < NumArgsTested(); i++) {
+ class_ids->Add(Smi::Value(Smi::RawCast(data.At(data_pos++))));
+ }
+}
+
+
void ICData::GetOneClassCheckAt(intptr_t index,
intptr_t* class_id,
Function* target) const {
@@ -12469,8 +12518,7 @@
intptr_t ICData::GetClassIdAt(intptr_t index, intptr_t arg_nr) const {
GrowableArray<intptr_t> class_ids;
- Function& target = Function::Handle();
- GetCheckAt(index, &class_ids, &target);
+ GetClassIdsAt(index, &class_ids);
return class_ids[arg_nr];
}
@@ -12646,12 +12694,11 @@
ASSERT(NumArgsTested() == 2);
first->Clear();
second->Clear();
- Function& target = Function::Handle();
GrowableArray<intptr_t> class_ids;
const intptr_t len = NumberOfChecks();
for (intptr_t i = 0; i < len; i++) {
if (GetCountAt(i) > 0) {
- GetCheckAt(i, &class_ids, &target);
+ GetClassIdsAt(i, &class_ids);
ASSERT(class_ids.length() == 2);
first->Add(class_ids[0]);
second->Add(class_ids[1]);
@@ -12894,13 +12941,12 @@
}
bool initialized = false;
- Function& t = Function::Handle();
const intptr_t len = NumberOfChecks();
GrowableArray<intptr_t> class_ids;
for (intptr_t i = 0; i < len; i++) {
if (IsUsedAt(i)) {
initialized = true;
- GetCheckAt(i, &class_ids, &t);
+ GetClassIdsAt(i, &class_ids);
for (intptr_t j = 0; j < class_ids.length(); j++) {
const intptr_t cid = class_ids[j];
if ((cid != kSmiCid) && (cid != kMintCid)) {
@@ -13333,7 +13379,7 @@
VerifiedMemory::Accept(region.start(), region.size());
CPU::FlushICache(instrs.EntryPoint(), instrs.size());
- code.set_compile_timestamp(OS::GetCurrentTimeMicros());
+ code.set_compile_timestamp(OS::GetCurrentTraceMicros());
CodeObservers::NotifyAll(name,
instrs.EntryPoint(),
assembler->prologue_offset(),
@@ -17292,19 +17338,13 @@
const int64_t right_value = other.AsInt64Value();
switch (operation) {
case Token::kADD: {
- if (((left_value < 0) != (right_value < 0)) ||
- ((left_value + right_value) < 0) == (left_value < 0)) {
+ if (!Utils::WillAddOverflow(left_value, right_value)) {
return Integer::New(left_value + right_value, space);
}
break;
}
case Token::kSUB: {
- // TODO(srdjan): Investigate why XCode 7 produces wrong code
- // if the comparison is inlined as in above (Token::kADD).
- const bool both_same_sign = (left_value < 0) == (right_value < 0);
- const bool result_same_sign_as_left =
- ((left_value - right_value) < 0) == (left_value < 0);
- if (both_same_sign || result_same_sign_as_left) {
+ if (!Utils::WillSubOverflow(left_value, right_value)) {
return Integer::New(left_value - right_value, space);
}
break;
@@ -19365,11 +19405,9 @@
Dart_WeakPersistentHandleFinalizer callback) {
ASSERT((callback != NULL && peer != NULL) ||
(callback == NULL && peer == NULL));
- const bool is_prologue = false;
// TODO(19482): Make API consistent for external size of strings/typed data.
const intptr_t external_size = 0;
return FinalizablePersistentHandle::New(Isolate::Current(),
- is_prologue,
referent,
peer,
callback,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7c40e63..4bf0896 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1065,7 +1065,6 @@
bool IsMixinApplication() const;
RawClass* GetPatchClass() const;
- void SetPatchClass(const Class& patch_class) const;
// Interfaces is an array of Types.
RawArray* interfaces() const { return raw_ptr()->interfaces_; }
@@ -1148,8 +1147,6 @@
void SetFields(const Array& value) const;
void AddField(const Field& field) const;
void AddFields(const GrowableArray<const Field*>& fields) const;
- intptr_t FindFieldIndex(const Field& field) const;
- RawField* FieldFromIndex(intptr_t idx) const;
// Returns an array of all fields of this class and its superclasses indexed
// by offset in words.
@@ -1163,7 +1160,6 @@
void SetFunctions(const Array& value) const;
void AddFunction(const Function& function) const;
void RemoveFunction(const Function& function) const;
- intptr_t FindFunctionIndex(const Function& function) const;
RawFunction* FunctionFromIndex(intptr_t idx) const;
intptr_t FindImplicitClosureFunctionIndex(const Function& needle) const;
RawFunction* ImplicitClosureFunctionFromIndex(intptr_t idx) const;
@@ -1238,6 +1234,8 @@
void set_is_prefinalized() const;
+ void ResetFinalization() const;
+
bool is_marked_for_parsing() const {
return MarkedForParsingBit::decode(raw_ptr()->state_bits_);
}
@@ -1486,6 +1484,7 @@
friend class Object;
friend class Type;
friend class Intrinsifier;
+ friend class Precompiler;
};
@@ -1719,8 +1718,8 @@
class PatchClass : public Object {
public:
RawClass* patched_class() const { return raw_ptr()->patched_class_; }
- RawClass* source_class() const { return raw_ptr()->source_class_; }
- RawScript* Script() const;
+ RawClass* origin_class() const { return raw_ptr()->origin_class_; }
+ RawScript* script() const { return raw_ptr()->script_; }
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawPatchClass));
@@ -1731,11 +1730,15 @@
}
static RawPatchClass* New(const Class& patched_class,
- const Class& source_class);
+ const Class& origin_class);
+
+ static RawPatchClass* New(const Class& patched_class,
+ const Script& source);
private:
void set_patched_class(const Class& value) const;
- void set_source_class(const Class& value) const;
+ void set_origin_class(const Class& value) const;
+ void set_script(const Script& value) const;
static RawPatchClass* New();
@@ -1872,10 +1875,11 @@
// Retrieving checks.
- // TODO(srdjan): GetCheckAt without target.
void GetCheckAt(intptr_t index,
GrowableArray<intptr_t>* class_ids,
Function* target) const;
+ void GetClassIdsAt(intptr_t index, GrowableArray<intptr_t>* class_ids) const;
+
// Only for 'num_args_checked == 1'.
void GetOneClassCheckAt(intptr_t index,
intptr_t* class_id,
@@ -2138,6 +2142,7 @@
RawClass* Owner() const;
RawClass* origin() const;
RawScript* script() const;
+ RawObject* RawOwner() const { return raw_ptr()->owner_; }
RawJSRegExp* regexp() const;
intptr_t string_specialization_cid() const;
@@ -2865,6 +2870,9 @@
bool is_reflectable() const {
return ReflectableBit::decode(raw_ptr()->kind_bits_);
}
+ void set_is_reflectable(bool value) const {
+ set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
+ }
bool is_double_initialized() const {
return DoubleInitializedBit::decode(raw_ptr()->kind_bits_);
}
@@ -2885,6 +2893,8 @@
RawClass* owner() const;
RawClass* origin() const; // Either mixin class, or same as owner().
+ RawScript* script() const;
+ RawObject* RawOwner() const { return raw_ptr()->owner_; }
RawAbstractType* type() const { return raw_ptr()->type_; }
// Used by class finalizer, otherwise initialized in constructor.
@@ -2903,6 +2913,12 @@
const AbstractType& type,
intptr_t token_pos);
+ static RawField* NewTopLevel(const String& name,
+ bool is_final,
+ bool is_const,
+ const Object& owner,
+ intptr_t token_pos);
+
// Allocate new field object, clone values from this field. The
// owner of the clone is new_owner.
RawField* Clone(const Class& new_owner) const;
@@ -3091,9 +3107,6 @@
void set_is_const(bool value) const {
set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_));
}
- void set_is_reflectable(bool value) const {
- set_kind_bits(ReflectableBit::update(value, raw_ptr()->kind_bits_));
- }
void set_owner(const Object& value) const {
StorePointer(&raw_ptr()->owner_, value.raw());
}
@@ -3319,6 +3332,8 @@
class ClassDictionaryIterator : public DictionaryIterator {
public:
enum IterationKind {
+ // TODO(hausner): fix call sites that use kIteratePrivate. There is only
+ // one top-level class per library left, not an array to iterate over.
kIteratePrivate,
kNoIteratePrivate
};
@@ -3326,7 +3341,9 @@
ClassDictionaryIterator(const Library& library,
IterationKind kind = kNoIteratePrivate);
- bool HasNext() const { return (next_ix_ < size_) || (anon_ix_ < anon_size_); }
+ bool HasNext() const {
+ return (next_ix_ < size_) || !toplevel_class_.IsNull();
+ }
// Returns a non-null raw class.
RawClass* GetNextClass();
@@ -3334,9 +3351,7 @@
private:
void MoveToNextClass();
- const Array& anon_array_;
- const int anon_size_; // Number of anonymous classes to iterate over.
- int anon_ix_; // Index of next anonymous class.
+ Class& toplevel_class_;
DISALLOW_COPY_AND_ASSIGN(ClassDictionaryIterator);
};
@@ -3379,6 +3394,10 @@
void SetLoadError(const Instance& error) const;
RawInstance* TransitiveLoadError() const;
+ void AddPatchClass(const Class& cls) const;
+ RawClass* GetPatchClass(const String& name) const;
+ void RemovePatchClass(const Class& cls) const;
+
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawLibrary));
}
@@ -3432,17 +3451,19 @@
void AddExport(const Namespace& ns) const;
void AddClassMetadata(const Class& cls,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t token_pos) const;
void AddFieldMetadata(const Field& field, intptr_t token_pos) const;
void AddFunctionMetadata(const Function& func, intptr_t token_pos) const;
- void AddLibraryMetadata(const Class& cls, intptr_t token_pos) const;
+ void AddLibraryMetadata(const Object& tl_owner, intptr_t token_pos) const;
void AddTypeParameterMetadata(const TypeParameter& param,
intptr_t token_pos) const;
RawObject* GetMetadata(const Object& obj) const;
- intptr_t num_anonymous_classes() const { return raw_ptr()->num_anonymous_; }
- RawArray* anonymous_classes() const { return raw_ptr()->anonymous_classes_; }
+ RawClass* toplevel_class() const {
+ return raw_ptr()->toplevel_class_;
+ }
+ void set_toplevel_class(const Class& value) const;
RawGrowableObjectArray* patch_classes() const {
return raw_ptr()->patch_classes_;
@@ -3590,7 +3611,7 @@
RawString* MakeMetadataName(const Object& obj) const;
RawField* GetMetadataField(const String& metaname) const;
- void AddMetadata(const Class& cls,
+ void AddMetadata(const Object& owner,
const String& name,
intptr_t token_pos) const;
@@ -3613,7 +3634,7 @@
RawArray* show_names() const { return raw_ptr()->show_names_; }
RawArray* hide_names() const { return raw_ptr()->hide_names_; }
- void AddMetadata(intptr_t token_pos, const Class& owner_class);
+ void AddMetadata(const Object& owner, intptr_t token_pos);
RawObject* GetMetadata() const;
static intptr_t InstanceSize() {
diff --git a/runtime/vm/object_graph.cc b/runtime/vm/object_graph.cc
index 2bc0d66..6c46997 100644
--- a/runtime/vm/object_graph.cc
+++ b/runtime/vm/object_graph.cc
@@ -173,7 +173,7 @@
void ObjectGraph::IterateObjects(ObjectGraph::Visitor* visitor) {
NoSafepointScope no_safepoint_scope_;
Stack stack(isolate());
- isolate()->IterateObjectPointers(&stack, false, false);
+ isolate()->IterateObjectPointers(&stack, false);
stack.TraverseGraph(visitor);
Unmarker::UnmarkAll(isolate());
}
@@ -186,7 +186,41 @@
RawObject* root_raw = root.raw();
stack.VisitPointer(&root_raw);
stack.TraverseGraph(visitor);
- // TODO(koda): Optimize if we only visited a small subgraph.
+ Unmarker::UnmarkAll(isolate());
+}
+
+
+class InstanceAccumulator : public ObjectVisitor {
+ public:
+ explicit InstanceAccumulator(ObjectGraph::Stack* stack,
+ intptr_t class_id,
+ Isolate* isolate)
+ : ObjectVisitor(isolate), stack_(stack), class_id_(class_id) { }
+
+ void VisitObject(RawObject* obj) {
+ if (obj->GetClassId() == class_id_) {
+ RawObject* rawobj = obj;
+ stack_->VisitPointer(&rawobj);
+ }
+ }
+
+ private:
+ ObjectGraph::Stack* stack_;
+ const intptr_t class_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(InstanceAccumulator);
+};
+
+
+void ObjectGraph::IterateObjectsFrom(intptr_t class_id,
+ ObjectGraph::Visitor* visitor) {
+ NoSafepointScope no_safepoint_scope_;
+ Stack stack(isolate());
+
+ InstanceAccumulator accumulator(&stack, class_id, isolate());
+ isolate()->heap()->IterateObjects(&accumulator);
+
+ stack.TraverseGraph(visitor);
Unmarker::UnmarkAll(isolate());
}
@@ -240,6 +274,13 @@
}
+intptr_t ObjectGraph::SizeReachableByInstance(const Object& obj) {
+ SizeVisitor total;
+ IterateObjectsFrom(obj, &total);
+ return total.size();
+}
+
+
intptr_t ObjectGraph::SizeRetainedByClass(intptr_t class_id) {
SizeVisitor total;
IterateObjects(&total);
@@ -251,6 +292,13 @@
}
+intptr_t ObjectGraph::SizeReachableByClass(intptr_t class_id) {
+ SizeVisitor total;
+ IterateObjectsFrom(class_id, &total);
+ return total.size();
+}
+
+
class RetainingPathVisitor : public ObjectGraph::Visitor {
public:
// We cannot use a GrowableObjectArray, since we must not trigger GC.
@@ -473,7 +521,7 @@
stream->WriteUnsigned(0);
{
WritePointerVisitor ptr_writer(isolate(), stream);
- isolate()->IterateObjectPointers(&ptr_writer, false, false);
+ isolate()->IterateObjectPointers(&ptr_writer, false);
}
stream->WriteUnsigned(0);
IterateObjects(&visitor);
diff --git a/runtime/vm/object_graph.h b/runtime/vm/object_graph.h
index 0a65bae..5187d5e 100644
--- a/runtime/vm/object_graph.h
+++ b/runtime/vm/object_graph.h
@@ -63,12 +63,15 @@
// Like 'IterateObjects', but restricted to objects reachable from 'root'
// (including 'root' itself).
void IterateObjectsFrom(const Object& root, Visitor* visitor);
+ void IterateObjectsFrom(intptr_t class_id, Visitor* visitor);
// The number of bytes retained by 'obj'.
intptr_t SizeRetainedByInstance(const Object& obj);
+ intptr_t SizeReachableByInstance(const Object& obj);
// The number of bytes retained by the set of all objects of the given class.
intptr_t SizeRetainedByClass(intptr_t class_id);
+ intptr_t SizeReachableByClass(intptr_t class_id);
// Finds some retaining path from the isolate roots to 'obj'. Populates the
// provided array with pairs of (object, offset from parent in words),
diff --git a/runtime/vm/object_id_ring_test.cc b/runtime/vm/object_id_ring_test.cc
index 986757a..27347ea 100644
--- a/runtime/vm/object_id_ring_test.cc
+++ b/runtime/vm/object_id_ring_test.cc
@@ -133,7 +133,7 @@
EXPECT(Dart_IsList(result));
EXPECT_VALID(Dart_ListLength(result, &list_length));
EXPECT_EQ(3, list_length);
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Heap* heap = isolate->heap();
ObjectIdRing* ring = isolate->object_id_ring();
ObjectIdRing::LookupResult kind = ObjectIdRing::kInvalid;
@@ -174,7 +174,7 @@
EXPECT_NE(RawObject::ToAddr(raw_obj1), RawObject::ToAddr(raw_object_moved1));
EXPECT_NE(RawObject::ToAddr(raw_obj2), RawObject::ToAddr(raw_object_moved2));
// Test that we still point at the same list.
- Dart_Handle moved_handle = Api::NewHandle(isolate, raw_object_moved1);
+ Dart_Handle moved_handle = Api::NewHandle(thread, raw_object_moved1);
EXPECT_VALID(moved_handle);
EXPECT(!Dart_IsNull(moved_handle));
EXPECT(Dart_IsList(moved_handle));
@@ -188,7 +188,7 @@
// Test that the ring table is updated with nulls when the old GC collects.
TEST_CASE(ObjectIdRingOldGCTest) {
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Heap* heap = isolate->heap();
ObjectIdRing* ring = isolate->object_id_ring();
@@ -199,7 +199,7 @@
Dart_EnterScope();
Dart_Handle result;
// Create a string in the old heap.
- result = Api::NewHandle(isolate, String::New("old", Heap::kOld));
+ result = Api::NewHandle(thread, String::New("old", Heap::kOld));
EXPECT_VALID(result);
intptr_t string_length = 0;
// Inspect string.
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index 90a346e..624e1fe 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -90,6 +90,7 @@
handle_message_function_(Function::null()),
library_load_error_table_(Array::null()),
compile_time_constants_(Array::null()),
+ unique_dynamic_targets_(Array::null()),
token_objects_(GrowableObjectArray::null()),
token_objects_map_(Array::null()),
megamorphic_cache_table_(GrowableObjectArray::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 193c847..db57663 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -444,6 +444,13 @@
compile_time_constants_ = value.raw();
}
+ RawArray* unique_dynamic_targets() const {
+ return unique_dynamic_targets_;
+ }
+ void set_unique_dynamic_targets(const Array& value) {
+ unique_dynamic_targets_ = value.raw();
+ }
+
RawGrowableObjectArray* token_objects() const {
return token_objects_;
}
@@ -570,6 +577,7 @@
RawObject** to_snapshot() {
return reinterpret_cast<RawObject**>(&compile_time_constants_);
}
+ RawArray* unique_dynamic_targets_;
RawGrowableObjectArray* token_objects_;
RawArray* token_objects_map_;
RawGrowableObjectArray* megamorphic_cache_table_;
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index a4b2215..15a0021 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3769,114 +3769,6 @@
}
-TEST_CASE(FindFieldIndex) {
- const char* kScriptChars =
- "class A {\n"
- " var a;\n"
- " var b;\n"
- "}\n"
- "class B {\n"
- " var d;\n"
- "}\n"
- "test() {\n"
- " new A();\n"
- " new B();\n"
- "}";
- Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(h_lib);
- Dart_Handle result = Dart_Invoke(h_lib, NewString("test"), 0, NULL);
- EXPECT_VALID(result);
- Library& lib = Library::Handle();
- lib ^= Api::UnwrapHandle(h_lib);
- EXPECT(!lib.IsNull());
- const Class& class_a = Class::Handle(GetClass(lib, "A"));
- const Array& class_a_fields = Array::Handle(class_a.fields());
- const Class& class_b = Class::Handle(GetClass(lib, "B"));
- const Field& field_a = Field::Handle(GetField(class_a, "a"));
- const Field& field_b = Field::Handle(GetField(class_a, "b"));
- const Field& field_d = Field::Handle(GetField(class_b, "d"));
- intptr_t field_a_index = class_a.FindFieldIndex(field_a);
- intptr_t field_b_index = class_a.FindFieldIndex(field_b);
- intptr_t field_d_index = class_a.FindFieldIndex(field_d);
- // Valid index.
- EXPECT_GE(field_a_index, 0);
- // Valid index.
- EXPECT_GE(field_b_index, 0);
- // Invalid index.
- EXPECT_EQ(field_d_index, -1);
- Field& field_a_from_index = Field::Handle();
- field_a_from_index ^= class_a_fields.At(field_a_index);
- ASSERT(!field_a_from_index.IsNull());
- // Same field.
- EXPECT_EQ(field_a.raw(), field_a_from_index.raw());
- Field& field_b_from_index = Field::Handle();
- field_b_from_index ^= class_a_fields.At(field_b_index);
- ASSERT(!field_b_from_index.IsNull());
- // Same field.
- EXPECT_EQ(field_b.raw(), field_b_from_index.raw());
-}
-
-
-TEST_CASE(FindFunctionIndex) {
- // Tests both FindFunctionIndex and FindImplicitClosureFunctionIndex.
- const char* kScriptChars =
- "class A {\n"
- " void a() {}\n"
- " Function b() { return a; }\n"
- "}\n"
- "class B {\n"
- " dynamic d() {}\n"
- "}\n"
- "var x;\n"
- "test() {\n"
- " x = new A().b();\n"
- " x();\n"
- " new B();\n"
- " return x;\n"
- "}";
- Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(h_lib);
- Dart_Handle result = Dart_Invoke(h_lib, NewString("test"), 0, NULL);
- EXPECT_VALID(result);
- Library& lib = Library::Handle();
- lib ^= Api::UnwrapHandle(h_lib);
- EXPECT(!lib.IsNull());
- const Class& class_a = Class::Handle(GetClass(lib, "A"));
- const Class& class_b = Class::Handle(GetClass(lib, "B"));
- const Function& func_a = Function::Handle(GetFunction(class_a, "a"));
- const Function& func_b = Function::Handle(GetFunction(class_a, "b"));
- const Function& func_d = Function::Handle(GetFunction(class_b, "d"));
- EXPECT(func_a.HasImplicitClosureFunction());
- const Function& func_x = Function::Handle(func_a.ImplicitClosureFunction());
- intptr_t func_a_index = class_a.FindFunctionIndex(func_a);
- intptr_t func_b_index = class_a.FindFunctionIndex(func_b);
- intptr_t func_d_index = class_a.FindFunctionIndex(func_d);
- intptr_t func_x_index = class_a.FindImplicitClosureFunctionIndex(func_x);
- // Valid index.
- EXPECT_GE(func_a_index, 0);
- // Valid index.
- EXPECT_GE(func_b_index, 0);
- // Invalid index.
- EXPECT_EQ(func_d_index, -1);
- // Valid index.
- EXPECT_GE(func_x_index, 0);
- Function& func_a_from_index = Function::Handle();
- func_a_from_index ^= class_a.FunctionFromIndex(func_a_index);
- EXPECT(!func_a_from_index.IsNull());
- // Same function.
- EXPECT_EQ(func_a.raw(), func_a_from_index.raw());
- Function& func_b_from_index = Function::Handle();
- func_b_from_index ^= class_a.FunctionFromIndex(func_b_index);
- EXPECT(!func_b_from_index.IsNull());
- // Same function.
- EXPECT_EQ(func_b.raw(), func_b_from_index.raw());
- // Retrieve implicit closure function.
- Function& func_x_from_index = Function::Handle();
- func_x_from_index ^= class_a.ImplicitClosureFunctionFromIndex(func_x_index);
- EXPECT_EQ(func_x.raw(), func_x_from_index.raw());
-}
-
-
TEST_CASE(FindClosureIndex) {
// Allocate the class first.
const String& class_name = String::Handle(Symbols::New("MyClass"));
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
new file mode 100644
index 0000000..3789a60
--- /dev/null
+++ b/runtime/vm/os_thread.cc
@@ -0,0 +1,241 @@
+// 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.
+
+#include "vm/os_thread.h"
+
+#include "vm/atomic.h"
+#include "vm/lockers.h"
+#include "vm/log.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+// The single thread local key which stores all the thread local data
+// for a thread.
+ThreadLocalKey OSThread::thread_key_ = kUnsetThreadLocalKey;
+OSThread* OSThread::thread_list_head_ = NULL;
+Mutex* OSThread::thread_list_lock_ = NULL;
+
+
+OSThread::OSThread() :
+ BaseThread(true),
+ id_(OSThread::GetCurrentThreadId()),
+ join_id_(OSThread::GetCurrentThreadJoinId()),
+ trace_id_(OSThread::GetCurrentThreadTraceId()),
+ name_(NULL),
+ timeline_block_lock_(new Mutex()),
+ timeline_block_(NULL),
+ thread_list_next_(NULL),
+ thread_interrupt_disabled_(1), // Thread interrupts disabled by default.
+ log_(new class Log()),
+ stack_base_(0),
+ thread_(NULL) {
+ AddThreadToList(this);
+}
+
+
+OSThread::~OSThread() {
+ RemoveThreadFromList(this);
+ delete log_;
+ log_ = NULL;
+ if (Timeline::recorder() != NULL) {
+ Timeline::recorder()->FinishBlock(timeline_block_);
+ }
+ timeline_block_ = NULL;
+ delete timeline_block_lock_;
+ free(name_);
+}
+
+
+void OSThread::DisableThreadInterrupts() {
+ ASSERT(OSThread::Current() == this);
+ AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_);
+}
+
+
+void OSThread::EnableThreadInterrupts() {
+ ASSERT(OSThread::Current() == this);
+ uintptr_t old =
+ AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
+ if (old == 1) {
+ // We just decremented from 1 to 0.
+ // Make sure the thread interrupter is awake.
+ ThreadInterrupter::WakeUp();
+ }
+ if (old == 0) {
+ // We just decremented from 0, this means we've got a mismatched pair
+ // of calls to EnableThreadInterrupts and DisableThreadInterrupts.
+ FATAL("Invalid call to OSThread::EnableThreadInterrupts()");
+ }
+}
+
+
+bool OSThread::ThreadInterruptsEnabled() {
+ return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0;
+}
+
+
+static void DeleteThread(void* thread) {
+ delete reinterpret_cast<OSThread*>(thread);
+}
+
+
+void OSThread::InitOnce() {
+ // Allocate the global OSThread lock.
+ ASSERT(thread_list_lock_ == NULL);
+ thread_list_lock_ = new Mutex();
+ ASSERT(thread_list_lock_ != NULL);
+
+ // Create the thread local key.
+ ASSERT(thread_key_ == kUnsetThreadLocalKey);
+ thread_key_ = CreateThreadLocal(DeleteThread);
+ ASSERT(thread_key_ != kUnsetThreadLocalKey);
+
+ // Create a new OSThread strcture and set it as the TLS.
+ OSThread* os_thread = new OSThread();
+ OSThread::SetCurrent(os_thread);
+ os_thread->set_name("Dart_Initialize");
+}
+
+
+void OSThread::Cleanup() {
+ if (thread_list_lock_ != NULL) {
+ // Delete the thread local key.
+ ASSERT(thread_key_ != kUnsetThreadLocalKey);
+ DeleteThreadLocal(thread_key_);
+ thread_key_ = kUnsetThreadLocalKey;
+
+ // Delete the global OSThread lock.
+ ASSERT(thread_list_lock_ != NULL);
+ delete thread_list_lock_;
+ thread_list_lock_ = NULL;
+ }
+}
+
+
+OSThread* OSThread::CreateAndSetUnknownThread() {
+ ASSERT(OSThread::Current() == NULL);
+ OSThread* os_thread = new OSThread();
+ OSThread::SetCurrent(os_thread);
+ os_thread->set_name("Unknown");
+ return os_thread;
+}
+
+
+bool OSThread::IsThreadInList(ThreadJoinId join_id) {
+ if (join_id == OSThread::kInvalidThreadJoinId) {
+ return false;
+ }
+ OSThreadIterator it;
+ while (it.HasNext()) {
+ ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
+ OSThread* t = it.Next();
+ // An address test is not sufficient because the allocator may recycle
+ // the address for another Thread. Test against the thread's join id.
+ if (t->join_id() == join_id) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+OSThread* OSThread::GetOSThreadFromThread(Thread* thread) {
+ ASSERT(thread->os_thread() != NULL);
+ return thread->os_thread();
+}
+
+
+void OSThread::AddThreadToList(OSThread* thread) {
+ ASSERT(thread != NULL);
+ ASSERT(thread_list_lock_ != NULL);
+ MutexLocker ml(thread_list_lock_);
+
+ ASSERT(thread->thread_list_next_ == NULL);
+
+#if defined(DEBUG)
+ {
+ // Ensure that we aren't already in the list.
+ OSThread* current = thread_list_head_;
+ while (current != NULL) {
+ ASSERT(current != thread);
+ current = current->thread_list_next_;
+ }
+ }
+#endif
+
+ // Insert at head of list.
+ thread->thread_list_next_ = thread_list_head_;
+ thread_list_head_ = thread;
+}
+
+
+void OSThread::RemoveThreadFromList(OSThread* thread) {
+ {
+ ASSERT(thread != NULL);
+ ASSERT(thread_list_lock_ != NULL);
+ MutexLocker ml(thread_list_lock_);
+ OSThread* current = thread_list_head_;
+ OSThread* previous = NULL;
+
+ // Scan across list and remove |thread|.
+ while (current != NULL) {
+ if (current == thread) {
+ // We found |thread|, remove from list.
+ if (previous == NULL) {
+ thread_list_head_ = thread->thread_list_next_;
+ } else {
+ previous->thread_list_next_ = current->thread_list_next_;
+ }
+ thread->thread_list_next_ = NULL;
+ break;
+ }
+ previous = current;
+ current = current->thread_list_next_;
+ }
+ }
+ // Check if this is the last thread. The last thread does a cleanup
+ // which removes the thread local key and the associated mutex.
+ if (thread_list_head_ == NULL) {
+ Cleanup();
+ }
+}
+
+
+void OSThread::SetCurrent(OSThread* current) {
+ OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
+}
+
+
+OSThreadIterator::OSThreadIterator() {
+ ASSERT(OSThread::thread_list_lock_ != NULL);
+ // Lock the thread list while iterating.
+ OSThread::thread_list_lock_->Lock();
+ next_ = OSThread::thread_list_head_;
+}
+
+
+OSThreadIterator::~OSThreadIterator() {
+ ASSERT(OSThread::thread_list_lock_ != NULL);
+ // Unlock the thread list when done.
+ OSThread::thread_list_lock_->Unlock();
+}
+
+
+bool OSThreadIterator::HasNext() const {
+ ASSERT(OSThread::thread_list_lock_ != NULL);
+ ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
+ return next_ != NULL;
+}
+
+
+OSThread* OSThreadIterator::Next() {
+ ASSERT(OSThread::thread_list_lock_ != NULL);
+ ASSERT(OSThread::thread_list_lock_->IsOwnedByCurrentThread());
+ OSThread* current = next_;
+ next_ = next_->thread_list_next_;
+ return current;
+}
+
+} // namespace dart
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index 5929ef4..9371b45 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -6,6 +6,7 @@
#define VM_OS_THREAD_H_
#include "platform/globals.h"
+#include "vm/allocation.h"
#include "vm/globals.h"
// Declare the OS-specific types ahead of defining the generic classes.
@@ -23,13 +24,128 @@
namespace dart {
-// Low-level operations on OS platform threads.
-// TODO(koda): Move to runtime/platform.
-class OSThread {
+// Forward declarations.
+class Log;
+class Mutex;
+class Thread;
+class TimelineEventBlock;
+
+class BaseThread {
public:
- static ThreadLocalKey kUnsetThreadLocalKey;
- static ThreadId kInvalidThreadId;
- static ThreadJoinId kInvalidThreadJoinId;
+ bool is_os_thread() const { return is_os_thread_; }
+
+ private:
+ explicit BaseThread(bool is_os_thread) : is_os_thread_(is_os_thread) {}
+ ~BaseThread() {}
+
+ bool is_os_thread_;
+
+ friend class Thread;
+ friend class OSThread;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BaseThread);
+};
+
+
+// Low-level operations on OS platform threads.
+class OSThread : public BaseThread {
+ public:
+ OSThread();
+ ~OSThread();
+
+ ThreadId id() const {
+ ASSERT(id_ != OSThread::kInvalidThreadId);
+ return id_;
+ }
+
+ ThreadJoinId join_id() const {
+ ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
+ return join_id_;
+ }
+
+ ThreadId trace_id() const {
+ ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
+ return trace_id_;
+ }
+
+ const char* name() const {
+ return name_;
+ }
+
+ void set_name(const char* name) {
+ ASSERT(OSThread::Current() == this);
+ ASSERT(name_ == NULL);
+ ASSERT(name != NULL);
+ name_ = strdup(name);
+ }
+
+ Mutex* timeline_block_lock() const {
+ return timeline_block_lock_;
+ }
+
+ // Only safe to access when holding |timeline_block_lock_|.
+ TimelineEventBlock* timeline_block() const {
+ return timeline_block_;
+ }
+
+ // Only safe to access when holding |timeline_block_lock_|.
+ void set_timeline_block(TimelineEventBlock* block) {
+ timeline_block_ = block;
+ }
+
+ Log* log() const { return log_; }
+
+ uword stack_base() const { return stack_base_; }
+ void set_stack_base(uword stack_base) { stack_base_ = stack_base; }
+
+ // Retrieve the stack address bounds for profiler.
+ bool GetProfilerStackBounds(uword* lower, uword* upper) const {
+ uword stack_upper = stack_base_;
+ if (stack_upper == 0) {
+ return false;
+ }
+ uword stack_lower = stack_upper - GetSpecifiedStackSize();
+ *lower = stack_lower;
+ *upper = stack_upper;
+ return true;
+ }
+
+ // Used to temporarily disable or enable thread interrupts.
+ void DisableThreadInterrupts();
+ void EnableThreadInterrupts();
+ bool ThreadInterruptsEnabled();
+
+ // The currently executing thread, or NULL if not yet initialized.
+ static OSThread* Current() {
+ BaseThread* thread = GetCurrentTLS();
+ OSThread* os_thread = NULL;
+ if (thread != NULL) {
+ if (thread->is_os_thread()) {
+ os_thread = reinterpret_cast<OSThread*>(thread);
+ } else {
+ Thread* vm_thread = reinterpret_cast<Thread*>(thread);
+ os_thread = GetOSThreadFromThread(vm_thread);
+ }
+ } else {
+ os_thread = CreateAndSetUnknownThread();
+ }
+ return os_thread;
+ }
+ static void SetCurrent(OSThread* current);
+
+ // TODO(5411455): Use flag to override default value and Validate the
+ // stack size by querying OS.
+ static uword GetSpecifiedStackSize() {
+ ASSERT(OSThread::kStackSizeBuffer < OSThread::GetMaxStackSize());
+ uword stack_size = OSThread::GetMaxStackSize() - OSThread::kStackSizeBuffer;
+ return stack_size;
+ }
+ static BaseThread* GetCurrentTLS() {
+ return reinterpret_cast<BaseThread*>(OSThread::GetThreadLocal(thread_key_));
+ }
+ static void SetCurrentTLS(uword value) {
+ SetThreadLocal(thread_key_, value);
+ }
typedef void (*ThreadStartFunction) (uword parameter);
typedef void (*ThreadDestructor) (void* parameter);
@@ -37,26 +153,95 @@
// Start a thread running the specified function. Returns 0 if the
// thread started successfuly and a system specific error code if
// the thread failed to start.
- static int Start(ThreadStartFunction function, uword parameters);
+ static int Start(
+ const char* name, ThreadStartFunction function, uword parameter);
static ThreadLocalKey CreateThreadLocal(ThreadDestructor destructor = NULL);
static void DeleteThreadLocal(ThreadLocalKey key);
static uword GetThreadLocal(ThreadLocalKey key) {
return ThreadInlineImpl::GetThreadLocal(key);
}
+ static ThreadId GetCurrentThreadId();
static void SetThreadLocal(ThreadLocalKey key, uword value);
static intptr_t GetMaxStackSize();
- static ThreadId GetCurrentThreadId();
- static ThreadId GetCurrentThreadTraceId();
- static intptr_t CurrentCurrentThreadIdAsIntPtr() {
- return ThreadIdToIntPtr(GetCurrentThreadId());
- }
- static ThreadJoinId GetCurrentThreadJoinId();
static void Join(ThreadJoinId id);
static intptr_t ThreadIdToIntPtr(ThreadId id);
static ThreadId ThreadIdFromIntPtr(intptr_t id);
static bool Compare(ThreadId a, ThreadId b);
static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
+
+ // Called at VM startup and shutdown.
+ static void InitOnce();
+
+ static bool IsThreadInList(ThreadJoinId join_id);
+
+ static const intptr_t kStackSizeBuffer = (4 * KB * kWordSize);
+
+ static const ThreadId kInvalidThreadId;
+ static const ThreadJoinId kInvalidThreadJoinId;
+
+ private:
+ // These methods should not be used in a generic way and hence
+ // are private, they have been added to solve the problem of
+ // accessing the VM thread structure from an OSThread object
+ // in the windows thread interrupter which is used for profiling.
+ // We could eliminate this requirement if the windows thread interrupter
+ // is implemented differently.
+ Thread* thread() const { return thread_; }
+ void set_thread(Thread* value) {
+ thread_ = value;
+ }
+
+ static void Cleanup();
+ static ThreadId GetCurrentThreadTraceId();
+ static ThreadJoinId GetCurrentThreadJoinId();
+ static OSThread* GetOSThreadFromThread(Thread* thread);
+ static void AddThreadToList(OSThread* thread);
+ static void RemoveThreadFromList(OSThread* thread);
+ static OSThread* CreateAndSetUnknownThread();
+
+ static ThreadLocalKey thread_key_;
+
+ const ThreadId id_;
+ const ThreadJoinId join_id_;
+ const ThreadId trace_id_; // Used to interface with tracing tools.
+ char* name_; // A name for this thread.
+
+ Mutex* timeline_block_lock_;
+ TimelineEventBlock* timeline_block_;
+
+ // All |Thread|s are registered in the thread list.
+ OSThread* thread_list_next_;
+
+ uintptr_t thread_interrupt_disabled_;
+ Log* log_;
+ uword stack_base_;
+ Thread* thread_;
+
+ static OSThread* thread_list_head_;
+ static Mutex* thread_list_lock_;
+
+ friend class OSThreadIterator;
+ friend class ThreadInterrupterWin;
+ friend class ThreadRegistry;
+};
+
+
+// Note that this takes the thread list lock, prohibiting threads from coming
+// on- or off-line.
+class OSThreadIterator : public ValueObject {
+ public:
+ OSThreadIterator();
+ ~OSThreadIterator();
+
+ // Returns false when there are no more threads left.
+ bool HasNext() const;
+
+ // Returns the current thread and moves forward.
+ OSThread* Next();
+
+ private:
+ OSThread* next_;
};
diff --git a/runtime/vm/os_thread_android.cc b/runtime/vm/os_thread_android.cc
index f1c3a44..6f7ff34 100644
--- a/runtime/vm/os_thread_android.cc
+++ b/runtime/vm/os_thread_android.cc
@@ -11,6 +11,7 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
@@ -18,7 +19,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}
@@ -36,7 +37,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, error_message); \
return result; \
@@ -64,14 +65,17 @@
class ThreadStartData {
public:
- ThreadStartData(OSThread::ThreadStartFunction function,
+ ThreadStartData(const char* name,
+ OSThread::ThreadStartFunction function,
uword parameter)
- : function_(function), parameter_(parameter) {}
+ : name_(name), function_(function), parameter_(parameter) {}
+ const char* name() const { return name_; }
OSThread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
+ const char* name_;
OSThread::ThreadStartFunction function_;
uword parameter_;
@@ -85,10 +89,16 @@
static void* ThreadStart(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
+ const char* name = data->name();
OSThread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
+ // Create new OSThread object and set as TLS for new thread.
+ OSThread* thread = new OSThread();
+ OSThread::SetCurrent(thread);
+ thread->set_name(name);
+
// Call the supplied thread start function handing it its parameters.
function(parameter);
@@ -96,7 +106,9 @@
}
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+ ThreadStartFunction function,
+ uword parameter) {
pthread_attr_t attr;
int result = pthread_attr_init(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
@@ -104,7 +116,7 @@
result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
RETURN_ON_PTHREAD_FAILURE(result);
- ThreadStartData* data = new ThreadStartData(function, parameter);
+ ThreadStartData* data = new ThreadStartData(name, function, parameter);
pthread_t tid;
result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -117,10 +129,10 @@
}
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
- static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
-ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
+const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
+ static_cast<ThreadJoinId>(0);
+
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/vm/os_thread_android.h b/runtime/vm/os_thread_android.h
index 061066e..c4f3981 100644
--- a/runtime/vm/os_thread_android.h
+++ b/runtime/vm/os_thread_android.h
@@ -20,13 +20,17 @@
typedef pid_t ThreadId;
typedef pthread_t ThreadJoinId;
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+
+
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
~ThreadInlineImpl() {}
static uword GetThreadLocal(ThreadLocalKey key) {
- static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
ASSERT(key != kUnsetThreadLocalKey);
return reinterpret_cast<uword>(pthread_getspecific(key));
}
diff --git a/runtime/vm/os_thread_linux.cc b/runtime/vm/os_thread_linux.cc
index f48b6b0..4a08b84 100644
--- a/runtime/vm/os_thread_linux.cc
+++ b/runtime/vm/os_thread_linux.cc
@@ -13,27 +13,16 @@
#include <sys/time.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
-static char* strerror_helper(int err, char* buffer, size_t bufsize) {
-#if !defined(__GLIBC__) || \
- ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
- // Use the standard version
- return strerror_r(err, buffer, bufsize) == 0 ?
- buffer : const_cast<char*>("strerror_r failed");
-#else
- // Use the gnu specific version
- return strerror_r(err, buffer, bufsize);
-#endif
-}
-
#define VALIDATE_PTHREAD_RESULT(result) \
if (result != 0) { \
const int kBufferSize = 1024; \
char error_buf[kBufferSize]; \
FATAL2("pthread error: %d (%s)", result, \
- strerror_helper(result, error_buf, kBufferSize)); \
+ Utils::StrError(result, error_buf, kBufferSize)); \
}
@@ -52,7 +41,7 @@
char error_buf[kBufferSize]; \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, \
- strerror_helper(result, error_buf, kBufferSize)); \
+ Utils::StrError(result, error_buf, kBufferSize)); \
return result; \
}
#else
@@ -78,14 +67,17 @@
class ThreadStartData {
public:
- ThreadStartData(OSThread::ThreadStartFunction function,
+ ThreadStartData(const char* name,
+ OSThread::ThreadStartFunction function,
uword parameter)
- : function_(function), parameter_(parameter) {}
+ : name_(name), function_(function), parameter_(parameter) {}
+ const char* name() const { return name_; }
OSThread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
+ const char* name_;
OSThread::ThreadStartFunction function_;
uword parameter_;
@@ -99,10 +91,16 @@
static void* ThreadStart(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
+ const char* name = data->name();
OSThread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
+ // Create new OSThread object and set as TLS for new thread.
+ OSThread* thread = new OSThread();
+ OSThread::SetCurrent(thread);
+ thread->set_name(name);
+
// Call the supplied thread start function handing it its parameters.
function(parameter);
@@ -110,7 +108,9 @@
}
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+ ThreadStartFunction function,
+ uword parameter) {
pthread_attr_t attr;
int result = pthread_attr_init(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
@@ -118,7 +118,7 @@
result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
RETURN_ON_PTHREAD_FAILURE(result);
- ThreadStartData* data = new ThreadStartData(function, parameter);
+ ThreadStartData* data = new ThreadStartData(name, function, parameter);
pthread_t tid;
result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -131,10 +131,10 @@
}
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
- static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
-ThreadJoinId OSThread::kInvalidThreadJoinId = static_cast<ThreadJoinId>(0);
+const ThreadId OSThread::kInvalidThreadId = static_cast<ThreadId>(0);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
+ static_cast<ThreadJoinId>(0);
+
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
pthread_key_t key = kUnsetThreadLocalKey;
diff --git a/runtime/vm/os_thread_linux.h b/runtime/vm/os_thread_linux.h
index 5901214..306229b 100644
--- a/runtime/vm/os_thread_linux.h
+++ b/runtime/vm/os_thread_linux.h
@@ -20,13 +20,17 @@
typedef pthread_t ThreadId;
typedef pthread_t ThreadJoinId;
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+
+
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
~ThreadInlineImpl() {}
static uword GetThreadLocal(ThreadLocalKey key) {
- static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
ASSERT(key != kUnsetThreadLocalKey);
return reinterpret_cast<uword>(pthread_getspecific(key));
}
diff --git a/runtime/vm/os_thread_macos.cc b/runtime/vm/os_thread_macos.cc
index 851a467..2fa58d8 100644
--- a/runtime/vm/os_thread_macos.cc
+++ b/runtime/vm/os_thread_macos.cc
@@ -19,6 +19,7 @@
#include <mach/thread_act.h> // NOLINT
#include "platform/assert.h"
+#include "platform/utils.h"
namespace dart {
@@ -26,7 +27,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
FATAL2("pthread error: %d (%s)", result, error_message); \
}
@@ -44,7 +45,7 @@
if (result != 0) { \
const int kBufferSize = 1024; \
char error_message[kBufferSize]; \
- strerror_r(result, error_message, kBufferSize); \
+ Utils::StrError(result, error_message, kBufferSize); \
fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
__FILE__, __LINE__, result, error_message); \
return result; \
@@ -57,14 +58,17 @@
class ThreadStartData {
public:
- ThreadStartData(OSThread::ThreadStartFunction function,
+ ThreadStartData(const char* name,
+ OSThread::ThreadStartFunction function,
uword parameter)
- : function_(function), parameter_(parameter) {}
+ : name_(name), function_(function), parameter_(parameter) {}
+ const char* name() const { return name_; }
OSThread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
+ const char* name_;
OSThread::ThreadStartFunction function_;
uword parameter_;
@@ -78,10 +82,16 @@
static void* ThreadStart(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
+ const char* name = data->name();
OSThread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
+ // Create new OSThread object and set as TLS for new thread.
+ OSThread* thread = new OSThread();
+ OSThread::SetCurrent(thread);
+ thread->set_name(name);
+
// Call the supplied thread start function handing it its parameters.
function(parameter);
@@ -89,7 +99,9 @@
}
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
+int OSThread::Start(const char* name,
+ ThreadStartFunction function,
+ uword parameter) {
pthread_attr_t attr;
int result = pthread_attr_init(&attr);
RETURN_ON_PTHREAD_FAILURE(result);
@@ -97,7 +109,7 @@
result = pthread_attr_setstacksize(&attr, OSThread::GetMaxStackSize());
RETURN_ON_PTHREAD_FAILURE(result);
- ThreadStartData* data = new ThreadStartData(function, parameter);
+ ThreadStartData* data = new ThreadStartData(name, function, parameter);
pthread_t tid;
result = pthread_create(&tid, &attr, ThreadStart, data);
@@ -110,12 +122,11 @@
}
-ThreadLocalKey OSThread::kUnsetThreadLocalKey =
- static_cast<pthread_key_t>(-1);
-ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
-ThreadJoinId OSThread::kInvalidThreadJoinId =
+const ThreadId OSThread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
+const ThreadJoinId OSThread::kInvalidThreadJoinId =
reinterpret_cast<ThreadJoinId>(NULL);
+
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
pthread_key_t key = kUnsetThreadLocalKey;
int result = pthread_key_create(&key, destructor);
diff --git a/runtime/vm/os_thread_macos.h b/runtime/vm/os_thread_macos.h
index 63b4f02..4909edf 100644
--- a/runtime/vm/os_thread_macos.h
+++ b/runtime/vm/os_thread_macos.h
@@ -20,6 +20,11 @@
typedef pthread_t ThreadId;
typedef pthread_t ThreadJoinId;
+
+static const ThreadLocalKey kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+
+
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
diff --git a/runtime/vm/os_thread_win.cc b/runtime/vm/os_thread_win.cc
index fd8de38..52fbd98 100644
--- a/runtime/vm/os_thread_win.cc
+++ b/runtime/vm/os_thread_win.cc
@@ -20,13 +20,17 @@
class ThreadStartData {
public:
- ThreadStartData(OSThread::ThreadStartFunction function, uword parameter)
- : function_(function), parameter_(parameter) {}
+ ThreadStartData(const char* name,
+ OSThread::ThreadStartFunction function,
+ uword parameter)
+ : name_(name), function_(function), parameter_(parameter) {}
+ const char* name() const { return name_; }
OSThread::ThreadStartFunction function() const { return function_; }
uword parameter() const { return parameter_; }
private:
+ const char* name_;
OSThread::ThreadStartFunction function_;
uword parameter_;
@@ -40,12 +44,18 @@
static unsigned int __stdcall ThreadEntry(void* data_ptr) {
ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
+ const char* name = data->name();
OSThread::ThreadStartFunction function = data->function();
uword parameter = data->parameter();
delete data;
MonitorData::GetMonitorWaitDataForThread();
+ // Create new OSThread object and set as TLS for new thread.
+ OSThread* thread = new OSThread();
+ OSThread::SetCurrent(thread);
+ thread->set_name(name);
+
// Call the supplied thread start function handing it its parameters.
function(parameter);
@@ -56,8 +66,10 @@
}
-int OSThread::Start(ThreadStartFunction function, uword parameter) {
- ThreadStartData* start_data = new ThreadStartData(function, parameter);
+int OSThread::Start(const char* name,
+ ThreadStartFunction function,
+ uword parameter) {
+ ThreadStartData* start_data = new ThreadStartData(name, function, parameter);
uint32_t tid;
uintptr_t thread = _beginthreadex(NULL, OSThread::GetMaxStackSize(),
ThreadEntry, start_data, 0, &tid);
@@ -74,9 +86,10 @@
return 0;
}
-ThreadLocalKey OSThread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-ThreadId OSThread::kInvalidThreadId = 0;
-ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+
+const ThreadId OSThread::kInvalidThreadId = 0;
+const ThreadJoinId OSThread::kInvalidThreadJoinId = 0;
+
ThreadLocalKey OSThread::CreateThreadLocal(ThreadDestructor destructor) {
ThreadLocalKey key = TlsAlloc();
@@ -115,6 +128,8 @@
ThreadJoinId OSThread::GetCurrentThreadJoinId() {
+ // TODO(zra): Use the thread handle as the join id in order to have a more
+ // reliable join on windows.
return ::GetCurrentThreadId();
}
@@ -261,8 +276,7 @@
}
-ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ =
- OSThread::kUnsetThreadLocalKey;
+ThreadLocalKey MonitorWaitData::monitor_wait_data_key_ = kUnsetThreadLocalKey;
Monitor::Monitor() {
@@ -312,8 +326,7 @@
void MonitorWaitData::ThreadExit() {
- if (MonitorWaitData::monitor_wait_data_key_ !=
- OSThread::kUnsetThreadLocalKey) {
+ if (MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey) {
uword raw_wait_data =
OSThread::GetThreadLocal(MonitorWaitData::monitor_wait_data_key_);
// Clear in case this is called a second time.
@@ -421,8 +434,7 @@
MonitorWaitData* MonitorData::GetMonitorWaitDataForThread() {
// Ensure that the thread local key for monitor wait data objects is
// initialized.
- ASSERT(MonitorWaitData::monitor_wait_data_key_ !=
- OSThread::kUnsetThreadLocalKey);
+ ASSERT(MonitorWaitData::monitor_wait_data_key_ != kUnsetThreadLocalKey);
// Get the MonitorWaitData object containing the event for this
// thread from thread local storage. Create it if it does not exist.
diff --git a/runtime/vm/os_thread_win.h b/runtime/vm/os_thread_win.h
index 5398182..790306d 100644
--- a/runtime/vm/os_thread_win.h
+++ b/runtime/vm/os_thread_win.h
@@ -20,13 +20,16 @@
typedef DWORD ThreadId;
typedef DWORD ThreadJoinId;
+
+static const ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
+
+
class ThreadInlineImpl {
private:
ThreadInlineImpl() {}
~ThreadInlineImpl() {}
static uword GetThreadLocal(ThreadLocalKey key) {
- static ThreadLocalKey kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
ASSERT(key != kUnsetThreadLocalKey);
return reinterpret_cast<uword>(TlsGetValue(key));
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index c3fb3fe..e20ff43 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/parser.h"
+#include "vm/flags.h"
+
+#ifndef DART_PRECOMPILED
#include "lib/invocation_mirror.h"
#include "platform/utils.h"
@@ -13,7 +16,6 @@
#include "vm/compiler_stats.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
-#include "vm/flags.h"
#include "vm/growable_array.h"
#include "vm/handles.h"
#include "vm/hash_table.h"
@@ -826,12 +828,11 @@
RawObject* Parser::ParseFunctionParameters(const Function& func) {
ASSERT(!func.IsNull());
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ Zone* zone = stack_zone.GetZone();
const Script& script = Script::Handle(zone, func.script());
const Class& owner = Class::Handle(zone, func.Owner());
ASSERT(!owner.IsNull());
@@ -862,6 +863,8 @@
}
return param_descriptor.raw();
} else {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
Error& error = Error::Handle();
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
@@ -1005,14 +1008,15 @@
}
-RawObject* Parser::ParseMetadata(const Class& cls, intptr_t token_pos) {
- Thread* thread = Thread::Current();
- Isolate* isolate = thread->isolate();
- StackZone stack_zone(thread);
- Zone* zone = stack_zone.GetZone();
+RawObject* Parser::ParseMetadata(const Field& meta_data) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
- const Script& script = Script::Handle(zone, cls.script());
+ Thread* thread = Thread::Current();
+ StackZone stack_zone(thread);
+ Zone* zone = stack_zone.GetZone();
+ const Class& owner_class = Class::Handle(zone, meta_data.owner());
+ const Script& script = Script::Handle(zone, meta_data.script());
+ const intptr_t token_pos = meta_data.token_pos();
// Parsing metadata can involve following paths in the parser that are
// normally used for expressions and assume current_function is non-null,
// so we create a fake function to use as the current_function rather than
@@ -1025,17 +1029,21 @@
false, // is_abstract
false, // is_external
false, // is_native
- cls,
+ Object::Handle(zone, meta_data.RawOwner()),
token_pos));
fake_function.set_is_debuggable(false);
ParsedFunction* parsed_function =
new ParsedFunction(thread, fake_function);
Parser parser(script, parsed_function, token_pos);
- parser.set_current_class(cls);
+ parser.set_current_class(owner_class);
RawObject* metadata = parser.EvaluateMetadata();
return metadata;
} else {
+ Thread* thread = Thread::Current();
+ Isolate* isolate = thread->isolate();
+ StackZone stack_zone(thread);
+ Zone* zone = stack_zone.GetZone();
Error& error = Error::Handle(zone);
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
@@ -1143,18 +1151,14 @@
// TODO(koda): Should there be a StackZone here?
Zone* zone = thread->zone();
- const Class& script_cls = Class::Handle(zone, field.origin());
- const Script& script = Script::Handle(zone, script_cls.script());
-
const String& field_name = String::Handle(zone, field.name());
String& init_name = String::Handle(zone,
Symbols::FromConcat(Symbols::InitPrefix(), field_name));
+ const Script& script = Script::Handle(zone, field.script());
Object& initializer_owner = Object::Handle(field.owner());
- if (field.owner() != field.origin()) {
- initializer_owner =
- PatchClass::New(Class::Handle(field.owner()), script_cls);
- }
+ initializer_owner =
+ PatchClass::New(Class::Handle(field.owner()), script);
const Function& initializer = Function::ZoneHandle(zone,
Function::New(init_name,
@@ -1845,6 +1849,13 @@
const bool no_explicit_default_values = false;
ParseFormalParameterList(no_explicit_default_values, false, &func_params);
+ // In top-level and mixin functions, the source may be in a different
+ // script than the script of the current class.
+ Object& sig_func_owner = Object::Handle(Z, current_class().raw());
+ if (current_class().script() != script_.raw()) {
+ sig_func_owner = PatchClass::New(current_class(), script_);
+ }
+
// The field 'is_static' has no meaning for signature functions.
const Function& signature_function = Function::Handle(Z,
Function::New(*parameter.name,
@@ -1854,18 +1865,18 @@
/* is_abstract = */ false,
/* is_external = */ false,
/* is_native = */ false,
- current_class(),
+ sig_func_owner,
parameter.name_pos));
signature_function.set_result_type(result_type);
signature_function.set_is_debuggable(false);
AddFormalParamsToFunction(&func_params, signature_function);
- const String& signature = String::Handle(Z,
- signature_function.Signature());
+ const String& signature =
+ String::Handle(Z, signature_function.Signature());
// Lookup the signature class, i.e. the class whose name is the signature.
// We only lookup in the current library, but not in its imports, and only
// create a new canonical signature class if it does not exist yet.
- Class& signature_class = Class::ZoneHandle(Z,
- library_.LookupLocalClass(signature));
+ Class& signature_class =
+ Class::ZoneHandle(Z, library_.LookupLocalClass(signature));
if (signature_class.IsNull()) {
signature_class = Class::NewSignatureClass(signature,
signature_function,
@@ -2522,7 +2533,7 @@
if (found) continue;
- field.RecordStore(Object::Handle(Z));
+ field.RecordStore(Object::null_object());
}
}
@@ -2689,12 +2700,12 @@
// List argumentNames.
// The missing implicit setter of the field has no argument names.
- nsm_args->Add(new(Z) LiteralNode(init_pos, Array::ZoneHandle(Z)));
+ nsm_args->Add(new(Z) LiteralNode(init_pos, Object::null_array()));
// List existingArgumentNames.
// There is no setter for the final field, thus there are
// no existing names.
- nsm_args->Add(new(Z) LiteralNode(init_pos, Array::ZoneHandle(Z)));
+ nsm_args->Add(new(Z) LiteralNode(init_pos, Object::null_array()));
AstNode* nsm_call =
MakeStaticCall(Symbols::NoSuchMethodError(),
@@ -4412,7 +4423,7 @@
void Parser::ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseEnumDeclaration");
const intptr_t declaration_pos = (metadata_pos > 0) ? metadata_pos
@@ -4454,7 +4465,7 @@
cls.set_is_synthesized_class();
cls.set_is_enum_class();
if (metadata_pos >= 0) {
- library_.AddClassMetadata(cls, toplevel_class, metadata_pos);
+ library_.AddClassMetadata(cls, tl_owner, metadata_pos);
}
cls.set_super_type(Type::Handle(Z, Type::ObjectType()));
pending_classes.Add(cls, Heap::kOld);
@@ -4462,7 +4473,7 @@
void Parser::ParseClassDeclaration(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseClassDeclaration");
bool is_patch = false;
@@ -4577,7 +4588,7 @@
cls.set_is_abstract();
}
if (metadata_pos >= 0) {
- library_.AddClassMetadata(cls, toplevel_class, metadata_pos);
+ library_.AddClassMetadata(cls, tl_owner, metadata_pos);
}
const bool is_mixin_declaration = (CurrentToken() == Token::kASSIGN);
@@ -4633,13 +4644,12 @@
}
if (is_patch) {
+ cls.set_is_patch();
// Apply the changes to the patched class looked up above.
ASSERT(obj.raw() == library_.LookupLocalObject(class_name));
// The patched class must not be finalized yet.
- const Class& orig_class = Class::Cast(obj);
- ASSERT(!orig_class.is_finalized());
- orig_class.SetPatchClass(cls);
- cls.set_is_patch();
+ ASSERT(!Class::Cast(obj).is_finalized());
+ library_.AddPatchClass(cls);
}
pending_classes.Add(cls, Heap::kOld);
@@ -4957,7 +4967,7 @@
void Parser::ParseMixinAppAlias(
const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseMixinAppAlias");
const intptr_t classname_pos = TokenPos();
@@ -5011,7 +5021,7 @@
ExpectSemicolon();
pending_classes.Add(mixin_application, Heap::kOld);
if (metadata_pos >= 0) {
- library_.AddClassMetadata(mixin_application, toplevel_class, metadata_pos);
+ library_.AddClassMetadata(mixin_application, tl_owner, metadata_pos);
}
}
@@ -5057,7 +5067,7 @@
void Parser::ParseTypedef(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseTypedef");
intptr_t declaration_pos = (metadata_pos > 0) ? metadata_pos : TokenPos();
@@ -5067,7 +5077,7 @@
if (FLAG_warn_mixin_typedef) {
ReportWarning(TokenPos(), "deprecated mixin application typedef");
}
- ParseMixinAppAlias(pending_classes, toplevel_class, metadata_pos);
+ ParseMixinAppAlias(pending_classes, tl_owner, metadata_pos);
return;
}
@@ -5178,7 +5188,7 @@
pending_classes.Add(function_type_alias, Heap::kOld);
if (metadata_pos >= 0) {
library_.AddClassMetadata(function_type_alias,
- toplevel_class,
+ tl_owner,
metadata_pos);
}
}
@@ -5415,6 +5425,7 @@
void Parser::ParseTopLevelVariable(TopLevel* top_level,
+ const Object& owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelVariable");
const bool is_const = (CurrentToken() == Token::kCONST);
@@ -5450,8 +5461,10 @@
const bool is_reflectable =
!(library_.is_dart_scheme() && library_.IsPrivate(var_name));
- field = Field::New(var_name, is_static, is_final, is_const, is_reflectable,
- current_class(), type, name_pos);
+
+ field = Field::NewTopLevel(var_name, is_final, is_const, owner, name_pos);
+ field.SetFieldType(type);
+ field.set_is_reflectable(is_reflectable);
field.SetStaticValue(Object::null_instance(), true);
top_level->AddField(field);
library_.AddObject(field, var_name);
@@ -5479,13 +5492,11 @@
/* is_abstract = */ false,
/* is_external = */ false,
/* is_native = */ false,
- current_class(),
+ owner,
name_pos);
getter.set_result_type(type);
getter.set_is_debuggable(false);
- if (library_.is_dart_scheme() && library_.IsPrivate(var_name)) {
- getter.set_is_reflectable(false);
- }
+ getter.set_is_reflectable(is_reflectable);
top_level->AddFunction(getter);
}
} else if (is_final) {
@@ -5532,6 +5543,7 @@
void Parser::ParseTopLevelFunction(TopLevel* top_level,
+ const Object& owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelFunction");
const intptr_t decl_begin_pos = TokenPos();
@@ -5623,7 +5635,7 @@
/* is_abstract = */ false,
is_external,
is_native,
- current_class(),
+ owner,
decl_begin_pos));
func.set_result_type(result_type);
func.set_end_token_pos(function_end_pos);
@@ -5639,6 +5651,12 @@
if (!is_patch) {
library_.AddObject(func, func_name);
} else {
+ // Need to remove the previously added function that is being patched.
+ const Class& toplevel_cls = Class::Handle(Z, library_.toplevel_class());
+ const Function& replaced_func =
+ Function::Handle(Z, toplevel_cls.LookupStaticFunction(func_name));
+ ASSERT(!replaced_func.IsNull());
+ toplevel_cls.RemoveFunction(replaced_func);
library_.ReplaceObject(func, func_name);
}
if (metadata_pos >= 0) {
@@ -5648,6 +5666,7 @@
void Parser::ParseTopLevelAccessor(TopLevel* top_level,
+ const Object& owner,
intptr_t metadata_pos) {
TRACE_PARSER("ParseTopLevelAccessor");
const intptr_t decl_begin_pos = TokenPos();
@@ -5778,7 +5797,7 @@
/* is_abstract = */ false,
is_external,
is_native,
- current_class(),
+ owner,
decl_begin_pos));
func.set_result_type(result_type);
func.set_end_token_pos(accessor_end_pos);
@@ -5795,6 +5814,14 @@
if (!is_patch) {
library_.AddObject(func, accessor_name);
} else {
+ // Need to remove the previously added accessor that is being patched.
+ const Class& toplevel_cls = Class::Handle(Z,
+ owner.IsClass() ? Class::Cast(owner).raw()
+ : PatchClass::Cast(owner).patched_class());
+ const Function& replaced_func =
+ Function::Handle(Z, toplevel_cls.LookupFunction(accessor_name));
+ ASSERT(!replaced_func.IsNull());
+ toplevel_cls.RemoveFunction(replaced_func);
library_.ReplaceObject(func, accessor_name);
}
if (metadata_pos >= 0) {
@@ -5821,8 +5848,8 @@
I->BlockClassFinalization();
Api::Scope api_scope(T);
Dart_Handle result = handler(tag,
- Api::NewHandle(I, library_.raw()),
- Api::NewHandle(I, url.raw()));
+ Api::NewHandle(T, library_.raw()),
+ Api::NewHandle(T, url.raw()));
I->UnblockClassFinalization();
if (Dart_IsError(result)) {
// In case of an error we append an explanatory error message to the
@@ -5874,7 +5901,8 @@
}
-void Parser::ParseLibraryImportExport(intptr_t metadata_pos) {
+void Parser::ParseLibraryImportExport(const Object& tl_owner,
+ intptr_t metadata_pos) {
bool is_import = (CurrentToken() == Token::kIMPORT);
bool is_export = (CurrentToken() == Token::kEXPORT);
ASSERT(is_import || is_export);
@@ -5959,7 +5987,7 @@
Namespace& ns = Namespace::Handle(Z,
Namespace::New(library, show_names, hide_names));
if (metadata_pos >= 0) {
- ns.AddMetadata(metadata_pos, current_class());
+ ns.AddMetadata(tl_owner, metadata_pos);
}
// Ensure that private dart:_ libraries are only imported into dart:
@@ -6022,7 +6050,7 @@
}
-void Parser::ParseLibraryDefinition() {
+void Parser::ParseLibraryDefinition(const Object& tl_owner) {
TRACE_PARSER("ParseLibraryDefinition");
// Handle the script tag.
@@ -6045,14 +6073,14 @@
}
ParseLibraryName();
if (metadata_pos >= 0) {
- library_.AddLibraryMetadata(current_class(), metadata_pos);
+ library_.AddLibraryMetadata(tl_owner, metadata_pos);
}
rewind_pos = TokenPos();
metadata_pos = SkipMetadata();
}
while ((CurrentToken() == Token::kIMPORT) ||
(CurrentToken() == Token::kEXPORT)) {
- ParseLibraryImportExport(metadata_pos);
+ ParseLibraryImportExport(tl_owner, metadata_pos);
rewind_pos = TokenPos();
metadata_pos = SkipMetadata();
}
@@ -6104,13 +6132,21 @@
SetPosition(0);
is_top_level_ = true;
TopLevel top_level(Z);
- Class& toplevel_class = Class::Handle(Z,
- Class::New(Symbols::TopLevel(), script_, TokenPos()));
- toplevel_class.set_library(library_);
+
+ Object& tl_owner = Object::Handle(Z);
+ Class& toplevel_class = Class::Handle(Z, library_.toplevel_class());
+ if (toplevel_class.IsNull()) {
+ toplevel_class = Class::New(Symbols::TopLevel(), script_, TokenPos());
+ toplevel_class.set_library(library_);
+ library_.set_toplevel_class(toplevel_class);
+ tl_owner = toplevel_class.raw();
+ } else {
+ tl_owner = PatchClass::New(toplevel_class, script_);
+ }
if (is_library_source() || is_patch_source()) {
set_current_class(toplevel_class);
- ParseLibraryDefinition();
+ ParseLibraryDefinition(tl_owner);
} else if (is_part_source()) {
ParsePartHeader();
}
@@ -6120,27 +6156,27 @@
set_current_class(cls); // No current class.
intptr_t metadata_pos = SkipMetadata();
if (CurrentToken() == Token::kCLASS) {
- ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+ ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
} else if (CurrentToken() == Token::kENUM) {
- ParseEnumDeclaration(pending_classes, toplevel_class, metadata_pos);
+ ParseEnumDeclaration(pending_classes, tl_owner, metadata_pos);
} else if ((CurrentToken() == Token::kTYPEDEF) &&
(LookaheadToken(1) != Token::kLPAREN)) {
set_current_class(toplevel_class);
- ParseTypedef(pending_classes, toplevel_class, metadata_pos);
+ ParseTypedef(pending_classes, tl_owner, metadata_pos);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
- ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+ ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
} else if (is_patch_source() && IsSymbol(Symbols::Patch()) &&
(LookaheadToken(1) == Token::kCLASS)) {
- ParseClassDeclaration(pending_classes, toplevel_class, metadata_pos);
+ ParseClassDeclaration(pending_classes, tl_owner, metadata_pos);
} else {
set_current_class(toplevel_class);
if (IsVariableDeclaration()) {
- ParseTopLevelVariable(&top_level, metadata_pos);
+ ParseTopLevelVariable(&top_level, tl_owner, metadata_pos);
} else if (IsFunctionDeclaration()) {
- ParseTopLevelFunction(&top_level, metadata_pos);
+ ParseTopLevelFunction(&top_level, tl_owner, metadata_pos);
} else if (IsTopLevelAccessor()) {
- ParseTopLevelAccessor(&top_level, metadata_pos);
+ ParseTopLevelAccessor(&top_level, tl_owner, metadata_pos);
} else if (CurrentToken() == Token::kEOS) {
break;
} else {
@@ -6149,19 +6185,16 @@
}
}
- if ((library_.num_anonymous_classes() == 0) ||
- (top_level.fields().length() > 0) ||
- (top_level.functions().length() > 0)) {
+ if (top_level.fields().length() > 0) {
toplevel_class.AddFields(top_level.fields());
- const intptr_t len = top_level.functions().length();
- const Array& array = Array::Handle(Z, Array::New(len, Heap::kOld));
- for (intptr_t i = 0; i < len; i++) {
- array.SetAt(i, *top_level.functions()[i]);
- }
- toplevel_class.SetFunctions(array);
- library_.AddAnonymousClass(toplevel_class);
- pending_classes.Add(toplevel_class, Heap::kOld);
}
+ for (intptr_t i = 0; i < top_level.functions().length(); i++) {
+ toplevel_class.AddFunction(*top_level.functions()[i]);
+ }
+ if (toplevel_class.is_finalized()) {
+ toplevel_class.ResetFinalization();
+ }
+ pending_classes.Add(toplevel_class, Heap::kOld);
}
@@ -6220,9 +6253,7 @@
void Parser::OpenAsyncClosure() {
TRACE_PARSER("OpenAsyncClosure");
-
async_temp_scope_ = current_block_->scope;
-
OpenAsyncTryBlock();
}
@@ -7440,7 +7471,7 @@
// Initialize variable with null.
variable = new(Z) LocalVariable(
assign_pos, ident, type);
- AstNode* null_expr = new(Z) LiteralNode(ident_pos, Instance::ZoneHandle(Z));
+ AstNode* null_expr = new(Z) LiteralNode(ident_pos, Object::null_instance());
initialization = new(Z) StoreLocalNode(
ident_pos, variable, null_expr);
}
@@ -10282,7 +10313,7 @@
arguments->Add(new(Z) LiteralNode(
type_pos, Integer::ZoneHandle(Z, Integer::New(type_pos))));
// Src value argument.
- arguments->Add(new(Z) LiteralNode(type_pos, Instance::ZoneHandle(Z)));
+ arguments->Add(new(Z) LiteralNode(type_pos, Object::null_instance()));
// Dst type name argument.
arguments->Add(new(Z) LiteralNode(type_pos, Symbols::Malformed()));
// Dst name argument.
@@ -10341,7 +10372,7 @@
Smi::New(InvocationMirror::EncodeType(im_call, im_type)))));
// List arguments.
if (function_arguments == NULL) {
- arguments->Add(new(Z) LiteralNode(call_pos, Array::ZoneHandle(Z)));
+ arguments->Add(new(Z) LiteralNode(call_pos, Object::null_array()));
} else {
ArrayNode* array = new(Z) ArrayNode(
call_pos,
@@ -10351,7 +10382,7 @@
}
// List argumentNames.
if (function_arguments == NULL) {
- arguments->Add(new(Z) LiteralNode(call_pos, Array::ZoneHandle(Z)));
+ arguments->Add(new(Z) LiteralNode(call_pos, Object::null_array()));
} else {
arguments->Add(new(Z) LiteralNode(call_pos, function_arguments->names()));
}
@@ -10554,7 +10585,7 @@
LocalVariable* left_temp = result->AddInitializer(lhs);
const intptr_t no_pos = Scanner::kNoSourcePos;
LiteralNode* null_operand =
- new(Z) LiteralNode(no_pos, Instance::ZoneHandle(Z));
+ new(Z) LiteralNode(no_pos, Object::null_instance());
LoadLocalNode* load_left_temp = new(Z) LoadLocalNode(no_pos, left_temp);
ComparisonNode* null_compare =
new(Z) ComparisonNode(no_pos,
@@ -12130,8 +12161,8 @@
}
const Array& args_descriptor = Array::Handle(Z,
ArgumentsDescriptor::New(num_arguments, arguments->names()));
- Object& result = Object::Handle(Z);
- result = DartEntry::InvokeFunction(constructor, arg_values, args_descriptor);
+ const Object& result = Object::Handle(Z,
+ DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
if (result.IsError()) {
// An exception may not occur in every parse attempt, i.e., the
// generated AST is not deterministic. Therefore mark the function as
@@ -13868,7 +13899,7 @@
primary = new(Z) LiteralNode(TokenPos(), Bool::False());
ConsumeToken();
} else if (token == Token::kNULL) {
- primary = new(Z) LiteralNode(TokenPos(), Instance::ZoneHandle(Z));
+ primary = new(Z) LiteralNode(TokenPos(), Object::null_instance());
ConsumeToken();
} else if (token == Token::kLPAREN) {
ConsumeToken();
@@ -13877,7 +13908,7 @@
SetAllowFunctionLiterals(saved_mode);
ExpectToken(Token::kRPAREN);
} else if (token == Token::kDOUBLE) {
- Double& double_value = Double::ZoneHandle(Z, CurrentDoubleLiteral());
+ const Double& double_value = Double::ZoneHandle(Z, CurrentDoubleLiteral());
if (double_value.IsNull()) {
ReportError("invalid double literal");
}
@@ -14339,3 +14370,90 @@
}
} // namespace dart
+
+
+#else // DART_PRECOMPILED
+
+
+namespace dart {
+
+DEFINE_FLAG(bool, enable_mirrors, true,
+ "Disable to make importing dart:mirrors an error.");
+DEFINE_FLAG(bool, load_deferred_eagerly, false,
+ "Load deferred libraries eagerly.");
+DEFINE_FLAG(bool, link_natives_lazily, false, "Link native calls lazily");
+
+LocalVariable* ParsedFunction::EnsureExpressionTemp() {
+ UNREACHABLE();
+ return NULL;
+}
+
+
+void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
+ UNREACHABLE();
+}
+
+
+void ParsedFunction::SetRegExpCompileData(
+ RegExpCompileData* regexp_compile_data) {
+ UNREACHABLE();
+}
+
+
+void ParsedFunction::AllocateVariables() {
+ UNREACHABLE();
+}
+
+
+void ParsedFunction::AllocateIrregexpVariables(intptr_t num_stack_locals) {
+ UNREACHABLE();
+}
+
+
+void Parser::ParseCompilationUnit(const Library& library,
+ const Script& script) {
+ UNREACHABLE();
+}
+
+
+void Parser::ParseClass(const Class& cls) {
+ UNREACHABLE();
+}
+
+
+RawObject* Parser::ParseFunctionParameters(const Function& func) {
+ UNREACHABLE();
+ return Object::null();
+}
+
+
+void Parser::ParseFunction(ParsedFunction* parsed_function) {
+ UNREACHABLE();
+}
+
+
+RawObject* Parser::ParseMetadata(const Field& meta_data) {
+ UNREACHABLE();
+ return Object::null();
+}
+
+
+ParsedFunction* Parser::ParseStaticFieldInitializer(const Field& field) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
+ArgumentListNode* Parser::BuildNoSuchMethodArguments(
+ intptr_t call_pos,
+ const String& function_name,
+ const ArgumentListNode& function_args,
+ const LocalVariable* temp_for_last_arg,
+ bool is_super_invocation) {
+ UNREACHABLE();
+ return NULL;
+}
+
+} // namespace dart
+
+#endif // DART_PRECOMPILED
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 433a0c4..98bb8a0 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -205,7 +205,7 @@
// Parse and evaluate the metadata expressions at token_pos in the
// class namespace of class cls (which can be the implicit toplevel
// class if the metadata is at the top-level).
- static RawObject* ParseMetadata(const Class& cls, intptr_t token_pos);
+ static RawObject* ParseMetadata(const Field& meta_data);
// Build a function containing the initializer expression of the
// given static field.
@@ -399,22 +399,25 @@
// Support for parsing of scripts.
void ParseTopLevel();
void ParseEnumDeclaration(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos);
void ParseEnumDefinition(const Class& cls);
void ParseClassDeclaration(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos);
void ParseClassDefinition(const Class& cls);
void ParseMixinAppAlias(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos);
void ParseTypedef(const GrowableObjectArray& pending_classes,
- const Class& toplevel_class,
+ const Object& tl_owner,
intptr_t metadata_pos);
- void ParseTopLevelVariable(TopLevel* top_level, intptr_t metadata_pos);
- void ParseTopLevelFunction(TopLevel* top_level, intptr_t metadata_pos);
- void ParseTopLevelAccessor(TopLevel* top_level, intptr_t metadata_pos);
+ void ParseTopLevelVariable(TopLevel* top_level,
+ const Object& owner, intptr_t metadata_pos);
+ void ParseTopLevelFunction(TopLevel* top_level,
+ const Object& owner, intptr_t metadata_pos);
+ void ParseTopLevelAccessor(TopLevel* top_level,
+ const Object& owner, intptr_t metadata_pos);
RawArray* EvaluateMetadata();
RawFunction::AsyncModifier ParseFunctionModifier();
@@ -424,9 +427,10 @@
intptr_t token_pos,
const String& url);
void ParseIdentList(GrowableObjectArray* names);
- void ParseLibraryDefinition();
+ void ParseLibraryDefinition(const Object& tl_owner);
void ParseLibraryName();
- void ParseLibraryImportExport(intptr_t metadata_pos);
+ void ParseLibraryImportExport(const Object& tl_owner,
+ intptr_t metadata_pos);
void ParseLibraryPart();
void ParsePartHeader();
void ParseLibraryNameObsoleteSyntax();
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 56e4ffc..0b533f0 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -4,8 +4,10 @@
#include "vm/precompiler.h"
+#include "vm/cha.h"
#include "vm/code_patcher.h"
#include "vm/compiler.h"
+#include "vm/hash_table.h"
#include "vm/isolate.h"
#include "vm/log.h"
#include "vm/longjump.h"
@@ -22,6 +24,10 @@
#define Z (zone())
+DEFINE_FLAG(bool, collect_dynamic_function_names, false,
+ "In precompilation collects all dynamic function names in order to"
+ " identify unique targets");
+DEFINE_FLAG(bool, print_unique_targets, false, "Print unique dynaic targets");
DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
@@ -94,6 +100,8 @@
// iterations.
ClearAllCode();
+ CollectDynamicFunctionNames();
+
// Start with the allocations and invocations that happen from C++.
AddRoots(embedder_entry_points);
@@ -124,12 +132,12 @@
void Precompiler::ClearAllCode() {
- class CodeCodeFunctionVisitor : public FunctionVisitor {
+ class ClearCodeFunctionVisitor : public FunctionVisitor {
void VisitFunction(const Function& function) {
function.ClearCode();
}
};
- CodeCodeFunctionVisitor visitor;
+ ClearCodeFunctionVisitor visitor;
VisitFunctions(&visitor);
}
@@ -588,6 +596,11 @@
class_count_++;
cls.set_is_allocated(true);
+ error_ = cls.EnsureIsFinalized(T);
+ if (!error_.IsNull()) {
+ Jump(error_);
+ }
+
changed_ = true;
if (FLAG_trace_precompiler) {
@@ -703,11 +716,161 @@
}
+class NameFunctionsTraits {
+ public:
+ static bool IsMatch(const Object& a, const Object& b) {
+ return a.IsString() && b.IsString() &&
+ String::Cast(a).Equals(String::Cast(b));
+ }
+ static uword Hash(const Object& obj) {
+ return String::Cast(obj).Hash();
+ }
+ static RawObject* NewKey(const String& str) {
+ return str.raw();
+ }
+};
+
+typedef UnorderedHashMap<NameFunctionsTraits> Table;
+
+
+class FunctionsTraits {
+ public:
+ static bool IsMatch(const Object& a, const Object& b) {
+ Zone* zone = Thread::Current()->zone();
+ String& a_s = String::Handle(zone);
+ String& b_s = String::Handle(zone);
+ a_s = a.IsFunction() ? Function::Cast(a).name() : String::Cast(a).raw();
+ b_s = b.IsFunction() ? Function::Cast(b).name() : String::Cast(b).raw();
+ ASSERT(a_s.IsSymbol() && b_s.IsSymbol());
+ return a_s.raw() == b_s.raw();
+ }
+ static uword Hash(const Object& obj) {
+ if (obj.IsFunction()) {
+ return String::Handle(Function::Cast(obj).name()).Hash();
+ } else {
+ ASSERT(String::Cast(obj).IsSymbol());
+ return String::Cast(obj).Hash();
+ }
+ }
+ static RawObject* NewKey(const Function& function) {
+ return function.raw();
+ }
+};
+
+typedef UnorderedHashSet<FunctionsTraits> UniqueFunctionsSet;
+
+
+static void AddNameToFunctionsTable(Zone* zone,
+ Table* table,
+ const String& fname,
+ const Function& function) {
+ Array& farray = Array::Handle(zone);
+ farray ^= table->InsertNewOrGetValue(fname, Array::empty_array());
+ farray = Array::Grow(farray, farray.Length() + 1);
+ farray.SetAt(farray.Length() - 1, function);
+ table->UpdateValue(fname, farray);
+}
+
+
+void Precompiler::CollectDynamicFunctionNames() {
+ if (!FLAG_collect_dynamic_function_names) {
+ return;
+ }
+ Library& lib = Library::Handle(Z);
+ Class& cls = Class::Handle(Z);
+ Array& functions = Array::Handle(Z);
+ Function& function = Function::Handle(Z);
+ String& fname = String::Handle(Z);
+ Array& farray = Array::Handle(Z);
+
+ Table table(HashTables::New<Table>(100));
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
+ while (it.HasNext()) {
+ cls = it.GetNextClass();
+ if (cls.IsDynamicClass()) {
+ continue; // class 'dynamic' is in the read-only VM isolate.
+ }
+ functions = cls.functions();
+ for (intptr_t j = 0; j < functions.Length(); j++) {
+ function ^= functions.At(j);
+ if (function.IsDynamicFunction()) {
+ fname = function.name();
+ if (function.IsSetterFunction() ||
+ function.IsImplicitSetterFunction()) {
+ AddNameToFunctionsTable(zone(), &table, fname, function);
+ } else if (function.IsGetterFunction() ||
+ function.IsImplicitGetterFunction()) {
+ // Enter both getter and non getter name.
+ AddNameToFunctionsTable(zone(), &table, fname, function);
+ fname = Field::NameFromGetter(fname);
+ AddNameToFunctionsTable(zone(), &table, fname, function);
+ } else {
+ // Regular function. Enter both getter and non getter name.
+ AddNameToFunctionsTable(zone(), &table, fname, function);
+ fname = Field::GetterName(fname);
+ AddNameToFunctionsTable(zone(), &table, fname, function);
+ }
+ }
+ }
+ }
+ }
+
+ // Locate all entries with one function only, and whose owner is neither
+ // subclassed nor implemented.
+ Table::Iterator iter(&table);
+ String& key = String::Handle(Z);
+ UniqueFunctionsSet functions_set(HashTables::New<UniqueFunctionsSet>(20));
+ while (iter.MoveNext()) {
+ intptr_t curr_key = iter.Current();
+ key ^= table.GetKey(curr_key);
+ farray ^= table.GetOrNull(key);
+ ASSERT(!farray.IsNull());
+ if (farray.Length() == 1) {
+ function ^= farray.At(0);
+ cls = function.Owner();
+ if (!CHA::IsImplemented(cls) && !CHA::HasSubclasses(cls)) {
+ functions_set.Insert(function);
+ }
+ }
+ }
+
+ if (FLAG_print_unique_targets) {
+ UniqueFunctionsSet::Iterator unique_iter(&functions_set);
+ while (unique_iter.MoveNext()) {
+ intptr_t curr_key = unique_iter.Current();
+ function ^= functions_set.GetKey(curr_key);
+ THR_Print("* %s\n", function.ToQualifiedCString());
+ }
+ THR_Print("%" Pd " of %" Pd " dynamic selectors are unique\n",
+ functions_set.NumOccupied(), table.NumOccupied());
+ }
+
+ isolate()->object_store()->set_unique_dynamic_targets(
+ functions_set.Release());
+ table.Release();
+}
+
+
+void Precompiler::GetUniqueDynamicTarget(Isolate* isolate,
+ const String& fname,
+ Object* function) {
+ UniqueFunctionsSet functions_set(
+ isolate->object_store()->unique_dynamic_targets());
+ ASSERT(fname.IsSymbol());
+ *function = functions_set.GetOrNull(fname);
+ ASSERT(functions_set.Release().raw() ==
+ isolate->object_store()->unique_dynamic_targets());
+}
+
+
void Precompiler::DropUncompiledFunctions() {
Library& lib = Library::Handle(Z);
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);
@@ -724,7 +887,16 @@
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 {
@@ -775,7 +947,10 @@
}
void VisitFunction(const Function& function) {
- ASSERT(function.HasCode());
+ if (!function.HasCode()) {
+ ASSERT(function.HasImplicitClosureFunction());
+ return;
+ }
code_ = function.CurrentCode();
table_ = code_.static_calls_target_table();
@@ -832,6 +1007,10 @@
}
void VisitFunction(const Function& function) {
+ if (!function.HasCode()) {
+ ASSERT(function.HasImplicitClosureFunction());
+ return;
+ }
code_ = function.CurrentCode();
stackmaps_ = code_.stackmaps();
if (stackmaps_.IsNull()) return;
@@ -871,6 +1050,7 @@
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);
@@ -892,6 +1072,15 @@
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();
@@ -922,7 +1111,10 @@
if (cls.IsDynamicClass()) {
continue; // class 'dynamic' is in the read-only VM isolate.
}
- cls.EnsureIsFinalized(T);
+ error_ = cls.EnsureIsFinalized(T);
+ if (!error_.IsNull()) {
+ Jump(error_);
+ }
}
}
I->set_all_classes_finalized(true);
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 3710edf..50f9551 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -93,6 +93,16 @@
Dart_QualifiedFunctionName embedder_entry_points[],
bool reset_fields);
+ // Returns named function that is a unique dynamic target, i.e.,
+ // - the target is identified by its name alone, since it occurs only once.
+ // - target's class has no subclasses, and neither is subclassed, i.e.,
+ // the receiver type can be only the function's class.
+ // Returns Function::null() if there is no unique dynamic target for
+ // given 'fname'. 'fname' must be a symbol.
+ static void GetUniqueDynamicTarget(Isolate* isolate,
+ const String& fname,
+ Object* function);
+
private:
Precompiler(Thread* thread, bool reset_fields);
@@ -115,6 +125,7 @@
void CheckForNewDynamicFunctions();
void DropUncompiledFunctions();
+ void CollectDynamicFunctionNames();
void BindStaticCalls();
void DedupStackmaps();
void ResetPrecompilerState();
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index d1d52b8..af80f9f 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -712,7 +712,6 @@
// We are executing Dart code. We have frame pointers.
dart_stack_walker->walk();
} else {
- sample->set_vm_tag(VMTag::kEmbedderTagId);
sample->SetAt(0, pc);
}
@@ -747,17 +746,19 @@
uword* stack_lower,
uword* stack_upper) {
ASSERT(thread != NULL);
- Isolate* isolate = thread->isolate();
- ASSERT(isolate != NULL);
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
ASSERT(stack_lower != NULL);
ASSERT(stack_upper != NULL);
#if defined(USING_SIMULATOR)
const bool in_dart_code = thread->IsExecutingDartCode();
if (in_dart_code) {
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate != NULL);
Simulator* simulator = isolate->simulator();
*stack_lower = simulator->StackBase();
*stack_upper = simulator->StackTop();
- } else if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper)) {
+ } else if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper)) {
// Could not get stack boundary.
return false;
}
@@ -765,7 +766,7 @@
return false;
}
#else
- if (!isolate->GetProfilerStackBounds(stack_lower, stack_upper) ||
+ if (!os_thread->GetProfilerStackBounds(stack_lower, stack_upper) ||
(*stack_lower == 0) || (*stack_upper == 0)) {
// Could not get stack boundary.
return false;
@@ -782,12 +783,12 @@
}
if ((sp < *stack_lower) || (sp >= *stack_upper)) {
- // Stack pointer is outside isolate stack boundary.
+ // Stack pointer is outside thread's stack boundary.
return false;
}
if ((fp < *stack_lower) || (fp >= *stack_upper)) {
- // Frame pointer is outside isolate stack boundary.
+ // Frame pointer is outside threads's stack boundary.
return false;
}
@@ -819,7 +820,7 @@
Isolate* isolate = thread->isolate();
ASSERT(sample_buffer != NULL);
Sample* sample = sample_buffer->ReserveSample();
- sample->Init(isolate, OS::GetCurrentTimeMicros(), tid);
+ sample->Init(isolate, OS::GetCurrentTraceMicros(), tid);
uword vm_tag = thread->vm_tag();
#if defined(USING_SIMULATOR)
// When running in the simulator, the runtime entry function address
@@ -859,6 +860,8 @@
void Profiler::SampleAllocation(Thread* thread, intptr_t cid) {
ASSERT(thread != NULL);
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
Isolate* isolate = thread->isolate();
if (!CheckIsolate(isolate)) {
return;
@@ -895,9 +898,7 @@
return;
}
- Sample* sample = SetupSample(thread,
- sample_buffer,
- OSThread::GetCurrentThreadId());
+ Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
sample->SetAllocationCid(cid);
ProfilerNativeStackWalker native_stack_walker(isolate,
sample,
@@ -909,9 +910,7 @@
sp);
native_stack_walker.walk();
} else if (exited_dart_code) {
- Sample* sample = SetupSample(thread,
- sample_buffer,
- OSThread::GetCurrentThreadId());
+ Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
sample->SetAllocationCid(cid);
ProfilerDartExitStackWalker dart_exit_stack_walker(thread,
isolate,
@@ -921,11 +920,8 @@
} else {
// Fall back.
uintptr_t pc = GetProgramCounter();
- Sample* sample = SetupSample(thread,
- sample_buffer,
- OSThread::GetCurrentThreadId());
+ Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
sample->SetAllocationCid(cid);
- sample->set_vm_tag(VMTag::kEmbedderTagId);
sample->SetAt(0, pc);
}
}
@@ -934,6 +930,8 @@
void Profiler::SampleThread(Thread* thread,
const InterruptedThreadState& state) {
ASSERT(thread != NULL);
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
Isolate* isolate = thread->isolate();
if (StubCode::HasBeenInitialized() &&
@@ -1002,9 +1000,7 @@
}
// Setup sample.
- Sample* sample = SetupSample(thread,
- sample_buffer,
- OSThread::GetCurrentThreadId());
+ Sample* sample = SetupSample(thread, sample_buffer, os_thread->id());
// Increment counter for vm tag.
VMTagCounters* counters = isolate->vm_tag_counters();
ASSERT(counters != NULL);
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index 7ed4c36..a35da30 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -152,12 +152,12 @@
explicit AllocationFilter(Isolate* isolate, intptr_t cid)
: SampleFilter(isolate),
cid_(cid),
- enable_embedder_ticks_(false) {
+ enable_vm_ticks_(false) {
}
bool FilterSample(Sample* sample) {
- if (!enable_embedder_ticks_ &&
- (sample->vm_tag() == VMTag::kEmbedderTagId)) {
+ if (!enable_vm_ticks_ &&
+ (sample->vm_tag() == VMTag::kVMTagId)) {
// We don't want to see embedder ticks in the test.
return false;
}
@@ -165,13 +165,13 @@
(sample->allocation_cid() == cid_);
}
- void set_enable_embedder_ticks(bool enable) {
- enable_embedder_ticks_ = enable;
+ void set_enable_vm_ticks(bool enable) {
+ enable_vm_ticks_ = enable;
}
private:
intptr_t cid_;
- bool enable_embedder_ticks_;
+ bool enable_vm_ticks_;
};
@@ -835,7 +835,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate, class_class.id());
- filter.set_enable_embedder_ticks(true);
+ filter.set_enable_vm_ticks(true);
profile.Build(thread, &filter, Profile::kNoTags);
// We should have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
@@ -864,7 +864,7 @@
HANDLESCOPE(thread);
Profile profile(isolate);
AllocationFilter filter(isolate, class_class.id());
- filter.set_enable_embedder_ticks(true);
+ filter.set_enable_vm_ticks(true);
profile.Build(thread, &filter, Profile::kNoTags);
// We should still only have one allocation sample.
EXPECT_EQ(1, profile.sample_count());
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 9b335eb..b178fed 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -614,6 +614,7 @@
friend class Scavenger;
friend class ScavengerVisitor;
friend class SizeExcludingClassVisitor; // GetClassId
+ friend class InstanceAccumulator; // GetClassId
friend class RetainingPathVisitor; // GetClassId
friend class SkippedCodeFunctions; // StorePointer
friend class InstructionsReader; // tags_ check
@@ -740,9 +741,10 @@
return reinterpret_cast<RawObject**>(&ptr()->patched_class_);
}
RawClass* patched_class_;
- RawClass* source_class_;
+ RawClass* origin_class_;
+ RawScript* script_;
RawObject** to() {
- return reinterpret_cast<RawObject**>(&ptr()->source_class_);
+ return reinterpret_cast<RawObject**>(&ptr()->script_);
}
friend class Function;
@@ -977,7 +979,7 @@
RawString* private_key_;
RawArray* dictionary_; // Top-level names in this library.
RawGrowableObjectArray* metadata_; // Metadata on classes, methods etc.
- RawArray* anonymous_classes_; // Classes containing top-level elements.
+ RawClass* toplevel_class_; // Class containing top-level elements.
RawGrowableObjectArray* patch_classes_;
RawArray* imports_; // List of Namespaces imported without prefix.
RawArray* exports_; // List of re-exported Namespaces.
@@ -994,7 +996,6 @@
Dart_NativeEntryResolver native_entry_resolver_; // Resolves natives.
Dart_NativeEntrySymbol native_entry_symbol_resolver_;
classid_t index_; // Library id number.
- classid_t num_anonymous_; // Number of entries in anonymous_classes_.
uint16_t num_imports_; // Number of entries in imports_.
int8_t load_state_; // Of type LibraryState.
bool corelib_imported_;
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index c492b79..38e1f17 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -81,7 +81,6 @@
// Set all the object fields.
READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
-
ASSERT(!cls.IsInFullSnapshot() || (kind == Snapshot::kFull));
} else {
cls ^= reader->ReadClassId(object_id);
@@ -1069,8 +1068,6 @@
// Set all non object fields.
library.StoreNonPointer(&library.raw_ptr()->index_,
reader->ReadClassIDValue());
- library.StoreNonPointer(&library.raw_ptr()->num_anonymous_,
- reader->ReadClassIDValue());
library.StoreNonPointer(&library.raw_ptr()->num_imports_,
reader->Read<uint16_t>());
library.StoreNonPointer(&library.raw_ptr()->load_state_,
@@ -1140,7 +1137,6 @@
ASSERT((kind == Snapshot::kFull) || !ptr()->is_in_fullsnapshot_);
// Write out all non object fields.
writer->WriteClassIDValue(ptr()->index_);
- writer->WriteClassIDValue(ptr()->num_anonymous_);
writer->Write<uint16_t>(ptr()->num_imports_);
writer->Write<int8_t>(ptr()->load_state_);
writer->Write<bool>(ptr()->corelib_imported_);
diff --git a/runtime/vm/runtime_entry.h b/runtime/vm/runtime_entry.h
index 97b5623..4004e4f 100644
--- a/runtime/vm/runtime_entry.h
+++ b/runtime/vm/runtime_entry.h
@@ -45,8 +45,7 @@
is_leaf_(is_leaf),
is_float_(is_float),
next_(NULL) {
- // Strip off const for registration.
- VMTag::RegisterRuntimeEntry(const_cast<RuntimeEntry*>(this));
+ VMTag::RegisterRuntimeEntry(this);
}
~RuntimeEntry() {}
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index c2822b5..6d9799e 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -255,12 +255,9 @@
class ScavengerWeakVisitor : public HandleVisitor {
public:
- // 'prologue_weak_were_strong' is currently only used for sanity checking.
- explicit ScavengerWeakVisitor(Scavenger* scavenger,
- bool prologue_weak_were_strong)
+ explicit ScavengerWeakVisitor(Scavenger* scavenger)
: HandleVisitor(Thread::Current()),
- scavenger_(scavenger),
- prologue_weak_were_strong_(prologue_weak_were_strong) {
+ scavenger_(scavenger) {
ASSERT(scavenger->heap_->isolate() == Thread::Current()->isolate());
}
@@ -269,8 +266,6 @@
reinterpret_cast<FinalizablePersistentHandle*>(addr);
RawObject** p = handle->raw_addr();
if (scavenger_->IsUnreachable(p)) {
- ASSERT(!handle->IsPrologueWeakPersistent() ||
- !prologue_weak_were_strong_);
handle->UpdateUnreachable(thread()->isolate());
} else {
handle->UpdateRelocated(thread()->isolate());
@@ -279,7 +274,6 @@
private:
Scavenger* scavenger_;
- bool prologue_weak_were_strong_;
DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor);
};
@@ -561,12 +555,9 @@
}
-void Scavenger::IterateRoots(Isolate* isolate,
- ScavengerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles) {
+void Scavenger::IterateRoots(Isolate* isolate, ScavengerVisitor* visitor) {
int64_t start = OS::GetCurrentTimeMicros();
isolate->VisitObjectPointers(visitor,
- visit_prologue_weak_persistent_handles,
StackFrameIterator::kDontValidateFrames);
int64_t middle = OS::GetCurrentTimeMicros();
IterateStoreBuffers(isolate, visitor);
@@ -600,81 +591,8 @@
}
-void Scavenger::IterateWeakReferences(Isolate* isolate,
- ScavengerVisitor* visitor) {
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- while (true) {
- WeakReferenceSet* queue = state->delayed_weak_reference_sets();
- if (queue == NULL) {
- // The delay queue is empty therefore no clean-up is required.
- return;
- }
- state->set_delayed_weak_reference_sets(NULL);
- while (queue != NULL) {
- WeakReferenceSet* reference_set = WeakReferenceSet::Pop(&queue);
- ASSERT(reference_set != NULL);
- intptr_t num_keys = reference_set->num_keys();
- intptr_t num_values = reference_set->num_values();
- if ((num_keys == 1) && (num_values == 1) &&
- reference_set->SingletonKeyEqualsValue()) {
- // We do not have to process sets that have just one key/value pair
- // and the key and value are identical.
- continue;
- }
- bool is_unreachable = true;
- // Test each key object for reachability. If a key object is
- // reachable, all value objects should be scavenged.
- for (intptr_t k = 0; k < num_keys; ++k) {
- if (!IsUnreachable(reference_set->get_key(k))) {
- for (intptr_t v = 0; v < num_values; ++v) {
- RawObject** raw_obj_addr = reference_set->get_value(v);
- RawObject* raw_obj = *raw_obj_addr;
- // Only visit heap objects which are in from space, aka new objects
- // not in to space. This avoids visiting a value multiple times
- // during a scavenge.
- if (raw_obj->IsHeapObject() &&
- raw_obj->IsNewObject() &&
- !to_->Contains(RawObject::ToAddr(raw_obj))) {
- visitor->VisitPointer(raw_obj_addr);
- }
- }
- is_unreachable = false;
- // Since we have found a key object that is reachable and all
- // value objects have been marked we can break out of iterating
- // this set and move on to the next set.
- break;
- }
- }
- // If all key objects are unreachable put the reference on a
- // delay queue. This reference will be revisited if another
- // reference is scavenged.
- if (is_unreachable) {
- state->DelayWeakReferenceSet(reference_set);
- }
- }
- if ((resolved_top_ < top_) || PromotedStackHasMore()) {
- ProcessToSpace(visitor);
- } else {
- // Break out of the loop if there has been no forward process.
- // All key objects in the weak reference sets are unreachable
- // so we reset the weak reference sets queue.
- state->set_delayed_weak_reference_sets(NULL);
- break;
- }
- }
- ASSERT(state->delayed_weak_reference_sets() == NULL);
- // All weak reference sets are zone allocated and unmarked references which
- // were on the delay queue will be freed when the zone is released in the
- // epilog callback.
-}
-
-
-void Scavenger::IterateWeakRoots(Isolate* isolate,
- HandleVisitor* visitor,
- bool visit_prologue_weak_persistent_handles) {
- isolate->VisitWeakPersistentHandles(visitor,
- visit_prologue_weak_persistent_handles);
+void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) {
+ isolate->VisitWeakPersistentHandles(visitor);
}
@@ -873,16 +791,12 @@
// Setup the visitor and run the scavenge.
ScavengerVisitor visitor(isolate, this, from);
page_space->AcquireDataLock();
- const bool prologue_weak_are_strong = !invoke_api_callbacks;
- IterateRoots(isolate, &visitor, prologue_weak_are_strong);
+ IterateRoots(isolate, &visitor);
int64_t start = OS::GetCurrentTimeMicros();
ProcessToSpace(&visitor);
int64_t middle = OS::GetCurrentTimeMicros();
- IterateWeakReferences(isolate, &visitor);
- ScavengerWeakVisitor weak_visitor(this, prologue_weak_are_strong);
- // Include the prologue weak handles, since we must process any promotion.
- const bool visit_prologue_weak_handles = true;
- IterateWeakRoots(isolate, &weak_visitor, visit_prologue_weak_handles);
+ ScavengerWeakVisitor weak_visitor(this);
+ IterateWeakRoots(isolate, &weak_visitor);
visitor.Finalize();
ProcessWeakTables();
page_space->ReleaseDataLock();
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index af3f129..11a0aa1 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -231,14 +231,10 @@
SemiSpace* Prologue(Isolate* isolate, bool invoke_api_callbacks);
void IterateStoreBuffers(Isolate* isolate, ScavengerVisitor* visitor);
void IterateObjectIdTable(Isolate* isolate, ScavengerVisitor* visitor);
- void IterateRoots(Isolate* isolate,
- ScavengerVisitor* visitor,
- bool visit_prologue_weak_persistent_handles);
+ void IterateRoots(Isolate* isolate, ScavengerVisitor* visitor);
void IterateWeakProperties(Isolate* isolate, ScavengerVisitor* visitor);
void IterateWeakReferences(Isolate* isolate, ScavengerVisitor* visitor);
- void IterateWeakRoots(Isolate* isolate,
- HandleVisitor* visitor,
- bool visit_prologue_weak_persistent_handles);
+ void IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor);
void ProcessToSpace(ScavengerVisitor* visitor);
uword ProcessWeakProperty(RawWeakProperty* raw_weak,
ScavengerVisitor* visitor);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 50d1aa4..ccc2d58 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -97,7 +97,7 @@
EmbedderServiceHandler* Service::isolate_service_handler_head_ = NULL;
EmbedderServiceHandler* Service::root_service_handler_head_ = NULL;
struct ServiceMethodDescriptor;
-ServiceMethodDescriptor* FindMethod(const char* method_name);
+const ServiceMethodDescriptor* FindMethod(const char* method_name);
// Support for streams defined in embedders.
@@ -491,7 +491,7 @@
class EnumParameter : public MethodParameter {
public:
- EnumParameter(const char* name, bool required, const char** enums)
+ EnumParameter(const char* name, bool required, const char* const* enums)
: MethodParameter(name, required),
enums_(enums) {
}
@@ -509,14 +509,14 @@
}
private:
- const char** enums_;
+ const char* const* enums_;
};
// If the key is not found, this function returns the last element in the
// values array. This can be used to encode the default value.
template<typename T>
-T EnumMapper(const char* value, const char** enums, T* values) {
+T EnumMapper(const char* value, const char* const* enums, T* values) {
ASSERT(value != NULL);
intptr_t i = 0;
for (i = 0; enums[i] != NULL; i++) {
@@ -644,7 +644,7 @@
}
const char* c_method_name = method_name.ToCString();
- ServiceMethodDescriptor* method = FindMethod(c_method_name);
+ const ServiceMethodDescriptor* method = FindMethod(c_method_name);
if (method != NULL) {
if (!ValidateParameters(method->parameters, &js)) {
js.PostReply();
@@ -1271,22 +1271,24 @@
return func.raw();
} else if (strcmp(parts[2], "fields") == 0) {
- // Field ids look like: "classes/17/fields/11"
+ // Field ids look like: "classes/17/fields/name"
if (num_parts != 4) {
return Object::sentinel().raw();
}
- intptr_t id;
- if (!GetIntegerId(parts[3], &id)) {
+ const char* encoded_id = parts[3];
+ String& id = String::Handle(zone, String::New(encoded_id));
+ id = String::DecodeIRI(id);
+ if (id.IsNull()) {
return Object::sentinel().raw();
}
- Field& field = Field::Handle(zone, cls.FieldFromIndex(id));
+ Field& field = Field::Handle(zone, cls.LookupField(id));
if (field.IsNull()) {
return Object::sentinel().raw();
}
return field.raw();
} else if (strcmp(parts[2], "functions") == 0) {
- // Function ids look like: "classes/17/functions/11"
+ // Function ids look like: "classes/17/functions/name"
if (num_parts != 4) {
return Object::sentinel().raw();
}
@@ -1385,12 +1387,12 @@
return Object::sentinel().raw();
}
uword pc;
- static const char* kCollectedPrefix = "collected-";
+ static const char* const kCollectedPrefix = "collected-";
static intptr_t kCollectedPrefixLen = strlen(kCollectedPrefix);
- static const char* kNativePrefix = "native-";
- static intptr_t kNativePrefixLen = strlen(kNativePrefix);
- static const char* kReusedPrefix = "reused-";
- static intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
+ static const char* const kNativePrefix = "native-";
+ static const intptr_t kNativePrefixLen = strlen(kNativePrefix);
+ static const char* const kReusedPrefix = "reused-";
+ static const intptr_t kReusedPrefixLen = strlen(kReusedPrefix);
const char* id = parts[1];
if (strncmp(kCollectedPrefix, id, kCollectedPrefixLen) == 0) {
if (!GetUnsignedIntegerId(&id[kCollectedPrefixLen], &pc, 16)) {
@@ -1764,16 +1766,14 @@
static const MethodParameter* get_retained_size_params[] = {
ISOLATE_PARAMETER,
+ new IdParameter("targetId", true),
NULL,
};
static bool GetRetainedSize(Thread* thread, JSONStream* js) {
const char* target_id = js->LookupParam("targetId");
- if (target_id == NULL) {
- PrintMissingParamError(js, "targetId");
- return true;
- }
+ ASSERT(target_id != NULL);
ObjectIdRing::LookupResult lookup_result;
Object& obj = Object::Handle(LookupHeapObject(thread, target_id,
&lookup_result));
@@ -1806,6 +1806,48 @@
}
+static const MethodParameter* get_reachable_size_params[] = {
+ ISOLATE_PARAMETER,
+ new IdParameter("targetId", true),
+ NULL,
+};
+
+
+static bool GetReachableSize(Thread* thread, JSONStream* js) {
+ const char* target_id = js->LookupParam("targetId");
+ ASSERT(target_id != NULL);
+ ObjectIdRing::LookupResult lookup_result;
+ Object& obj = Object::Handle(LookupHeapObject(thread, target_id,
+ &lookup_result));
+ if (obj.raw() == Object::sentinel().raw()) {
+ if (lookup_result == ObjectIdRing::kCollected) {
+ PrintSentinel(js, kCollectedSentinel);
+ } else if (lookup_result == ObjectIdRing::kExpired) {
+ PrintSentinel(js, kExpiredSentinel);
+ } else {
+ PrintInvalidParamError(js, "targetId");
+ }
+ return true;
+ }
+ // TODO(rmacnak): There is no way to get the size retained by a class object.
+ // SizeRetainedByClass should be a separate RPC.
+ if (obj.IsClass()) {
+ const Class& cls = Class::Cast(obj);
+ ObjectGraph graph(thread);
+ intptr_t retained_size = graph.SizeReachableByClass(cls.id());
+ const Object& result = Object::Handle(Integer::New(retained_size));
+ result.PrintJSON(js, true);
+ return true;
+ }
+
+ ObjectGraph graph(thread);
+ intptr_t retained_size = graph.SizeReachableByInstance(obj);
+ const Object& result = Object::Handle(Integer::New(retained_size));
+ result.PrintJSON(js, true);
+ return true;
+}
+
+
static const MethodParameter* evaluate_params[] = {
ISOLATE_PARAMETER,
NULL,
@@ -2446,14 +2488,14 @@
return true;
}
// Verify id begins with "metrics/".
- static const char* kMetricIdPrefix = "metrics/";
+ static const char* const kMetricIdPrefix = "metrics/";
static intptr_t kMetricIdPrefixLen = strlen(kMetricIdPrefix);
if (strncmp(metric_id, kMetricIdPrefix, kMetricIdPrefixLen) != 0) {
PrintInvalidParamError(js, "metricId");
return true;
}
// Check if id begins with "metrics/native/".
- static const char* kNativeMetricIdPrefix = "metrics/native/";
+ static const char* const kNativeMetricIdPrefix = "metrics/native/";
static intptr_t kNativeMetricIdPrefixLen = strlen(kNativeMetricIdPrefix);
const bool native_metric =
strncmp(metric_id, kNativeMetricIdPrefix, kNativeMetricIdPrefixLen) == 0;
@@ -2662,7 +2704,7 @@
}
-static const char* tags_enum_names[] = {
+static const char* const tags_enum_names[] = {
"None",
"UserVM",
"UserOnly",
@@ -2672,7 +2714,7 @@
};
-static Profile::TagOrder tags_enum_values[] = {
+static const Profile::TagOrder tags_enum_values[] = {
Profile::kNoTags,
Profile::kUserVM,
Profile::kUser,
@@ -3397,7 +3439,7 @@
}
-static ServiceMethodDescriptor service_methods_[] = {
+static const ServiceMethodDescriptor service_methods_[] = {
{ "_dumpIdZone", DumpIdZone, NULL },
{ "_echo", Echo,
NULL },
@@ -3455,6 +3497,8 @@
get_object_by_address_params },
{ "_getPorts", GetPorts,
get_ports_params },
+ { "_getReachableSize", GetReachableSize,
+ get_reachable_size_params },
{ "_getRetainedSize", GetRetainedSize,
get_retained_size_params },
{ "_getRetainingPath", GetRetainingPath,
@@ -3504,11 +3548,11 @@
};
-ServiceMethodDescriptor* FindMethod(const char* method_name) {
+const ServiceMethodDescriptor* FindMethod(const char* method_name) {
intptr_t num_methods = sizeof(service_methods_) /
sizeof(service_methods_[0]);
for (intptr_t i = 0; i < num_methods; i++) {
- ServiceMethodDescriptor& method = service_methods_[i];
+ const ServiceMethodDescriptor& method = service_methods_[i];
if (strcmp(method_name, method.name) == 0) {
return &method;
}
diff --git a/runtime/vm/service/service.md b/runtime/vm/service/service.md
index d824d4d..e71169d 100644
--- a/runtime/vm/service/service.md
+++ b/runtime/vm/service/service.md
@@ -1134,6 +1134,11 @@
//
// This is provided for the WriteEvent event.
string bytes [optional];
+
+ // The argument passed to dart:developer.inspect.
+ //
+ // This is provided for the Inspect event.
+ @Instance inspectee [optional];
}
```
@@ -1196,7 +1201,10 @@
GC,
// Notification of bytes written, for example, to stdout/stderr.
- WriteEvent
+ WriteEvent,
+
+ // Notification from dart:developer.inspect.
+ Inspect
}
```
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 1f70a67..eddb622 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -161,7 +161,7 @@
" x();\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Library& vmlib = Library::Handle();
@@ -184,7 +184,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -267,7 +267,7 @@
"main() {\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
@@ -288,7 +288,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -326,7 +326,7 @@
" x();\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Library& vmlib = Library::Handle();
@@ -350,7 +350,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -387,7 +387,7 @@
" x();\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Library& vmlib = Library::Handle();
@@ -411,7 +411,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -437,14 +437,14 @@
"main() {\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -518,7 +518,6 @@
Dart_RegisterRootServiceRequestCallback("alpha", alpha_callback, NULL);
Dart_RegisterRootServiceRequestCallback("beta", beta_callback, NULL);
- Isolate* isolate = Isolate::Current();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -527,7 +526,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -559,7 +558,7 @@
Dart_RegisterIsolateServiceRequestCallback("alpha", alpha_callback, NULL);
Dart_RegisterIsolateServiceRequestCallback("beta", beta_callback, NULL);
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -568,7 +567,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
@@ -598,7 +597,7 @@
" x = x / 13;\n"
"}";
- Isolate* isolate = Isolate::Current();
+ Isolate* isolate = thread->isolate();
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
@@ -607,7 +606,7 @@
// Build a mock message handler and wrap it in a dart port.
ServiceTestMessageHandler handler;
Dart_Port port_id = PortMap::CreatePort(&handler);
- Dart_Handle port = Api::NewHandle(isolate, SendPort::New(port_id));
+ Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
EXPECT_VALID(port);
EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 74464c8..f3e6514 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -700,8 +700,8 @@
// the size specified by the user and the buffer space needed for
// handling stack overflow exceptions. To be safe in potential
// stack underflows we also add some underflow buffer space.
- stack_ = new char[(Isolate::GetSpecifiedStackSize() +
- Isolate::kStackSizeBuffer +
+ stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+ OSThread::kStackSizeBuffer +
kSimulatorStackUnderflowSize)];
pc_modified_ = false;
icount_ = 0;
@@ -1177,7 +1177,7 @@
// To be safe in potential stack underflows we leave some buffer above and
// set the stack top.
return StackBase() +
- (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+ (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
}
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index cf25e24..0f1ed56 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -746,8 +746,8 @@
// the size specified by the user and the buffer space needed for
// handling stack overflow exceptions. To be safe in potential
// stack underflows we also add some underflow buffer space.
- stack_ = new char[(Isolate::GetSpecifiedStackSize() +
- Isolate::kStackSizeBuffer +
+ stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+ OSThread::kStackSizeBuffer +
kSimulatorStackUnderflowSize)];
pc_modified_ = false;
icount_ = 0;
@@ -1055,7 +1055,7 @@
// To be safe in potential stack underflows we leave some buffer above and
// set the stack top.
return StackBase() +
- (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+ (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
}
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index 04e0b7f..5fabae7 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -699,8 +699,8 @@
// the size specified by the user and the buffer space needed for
// handling stack overflow exceptions. To be safe in potential
// stack underflows we also add some underflow buffer space.
- stack_ = new char[(Isolate::GetSpecifiedStackSize() +
- Isolate::kStackSizeBuffer +
+ stack_ = new char[(OSThread::GetSpecifiedStackSize() +
+ OSThread::kStackSizeBuffer +
kSimulatorStackUnderflowSize)];
icount_ = 0;
delay_slot_ = false;
@@ -997,7 +997,7 @@
// To be safe in potential stack underflows we leave some buffer above and
// set the stack top.
return StackBase() +
- (Isolate::GetSpecifiedStackSize() + Isolate::kStackSizeBuffer);
+ (OSThread::GetSpecifiedStackSize() + OSThread::kStackSizeBuffer);
}
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 8e6c28e..a57296f 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -1622,6 +1622,7 @@
#define VM_OBJECT_CLASS_LIST(V) \
V(OneByteString) \
+ V(TwoByteString) \
V(Mint) \
V(Bigint) \
V(Double) \
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 1b73e39..c67a8ce 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -1074,7 +1074,7 @@
// Create a test library and Load up a test script in it.
TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
// Write out the script snapshot.
result = Dart_CreateScriptSnapshot(&buffer, &size);
@@ -1177,7 +1177,7 @@
// Create a test library and Load up a test script in it.
TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread));
timer1.Stop();
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
@@ -1238,7 +1238,7 @@
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
- EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread->isolate()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(thread));
timer1.Stop();
OS::PrintErr("Without Snapshot: %" Pd64 "us\n", timer1.TotalElapsedTime());
@@ -1382,7 +1382,7 @@
EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
import_lib,
Dart_Null()));
- EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
// Get list of library URLs loaded and save the count.
Dart_Handle libs = Dart_GetLibraryIds();
@@ -1618,7 +1618,7 @@
EXPECT_VALID(Dart_LibraryImportLibrary(TestCase::lib(),
import_lib,
Dart_Null()));
- EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Isolate::Current()));
+ EXPECT_VALID(Api::CheckAndFinalizePendingClasses(Thread::Current()));
// Write out the script snapshot.
result = Dart_CreateScriptSnapshot(&buffer, &size);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 3ec07cb..65f7c3b 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -283,12 +283,11 @@
}
-// TODO(johnmccutchan): Remove |isolate| argument.
// Tell MemorySanitizer that generated code initializes part of the stack.
// TODO(koda): Limit to frames that are actually written by generated code.
-static void UnpoisonStack(Isolate* isolate, uword fp) {
+static void UnpoisonStack(uword fp) {
ASSERT(fp != 0);
- uword size = isolate->GetSpecifiedStackSize();
+ uword size = OSThread::GetSpecifiedStackSize();
MSAN_UNPOISON(reinterpret_cast<void*>(fp - size), 2 * size);
}
@@ -355,7 +354,7 @@
if (!HasNextFrame()) {
return NULL;
}
- UnpoisonStack(thread_->isolate(), frames_.fp_);
+ UnpoisonStack(frames_.fp_);
if (frames_.pc_ == 0) {
// Iteration starts from an exit frame given by its fp.
current_frame_ = NextExitFrame();
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 8c197ae..7624fa2 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -786,7 +786,7 @@
// Copy the C stack pointer (R31) into the stack pointer we'll actually use
// to access the stack, and put the C stack pointer at the stack limit.
- __ SetupDartSP(Isolate::GetSpecifiedStackSize());
+ __ SetupDartSP(OSThread::GetSpecifiedStackSize());
__ EnterFrame(0);
// Push code object to PC marker slot.
diff --git a/runtime/vm/thread.cc b/runtime/vm/thread.cc
index 0d84937..db6f42e 100644
--- a/runtime/vm/thread.cc
+++ b/runtime/vm/thread.cc
@@ -4,6 +4,7 @@
#include "vm/thread.h"
+#include "vm/dart_api_state.h"
#include "vm/growable_array.h"
#include "vm/isolate.h"
#include "vm/lockers.h"
@@ -20,183 +21,9 @@
namespace dart {
-// The single thread local key which stores all the thread local data
-// for a thread.
-ThreadLocalKey Thread::thread_key_ = OSThread::kUnsetThreadLocalKey;
-Thread* Thread::thread_list_head_ = NULL;
-Mutex* Thread::thread_list_lock_ = NULL;
-
-// Remove |thread| from each isolate's thread registry.
-class ThreadPruner : public IsolateVisitor {
- public:
- explicit ThreadPruner(Thread* thread)
- : thread_(thread) {
- ASSERT(thread_ != NULL);
- }
-
- void VisitIsolate(Isolate* isolate) {
- ThreadRegistry* registry = isolate->thread_registry();
- ASSERT(registry != NULL);
- registry->PruneThread(thread_);
- }
- private:
- Thread* thread_;
-};
-
-
-void Thread::AddThreadToList(Thread* thread) {
- ASSERT(thread != NULL);
- ASSERT(thread->isolate() == NULL);
- ASSERT(thread_list_lock_ != NULL);
- MutexLocker ml(thread_list_lock_);
-
- ASSERT(thread->thread_list_next_ == NULL);
-
-#if defined(DEBUG)
- {
- // Ensure that we aren't already in the list.
- Thread* current = thread_list_head_;
- while (current != NULL) {
- ASSERT(current != thread);
- current = current->thread_list_next_;
- }
- }
-#endif
-
- // Insert at head of list.
- thread->thread_list_next_ = thread_list_head_;
- thread_list_head_ = thread;
-}
-
-
-void Thread::RemoveThreadFromList(Thread* thread) {
- ASSERT(thread != NULL);
- ASSERT(thread->isolate() == NULL);
- ASSERT(thread_list_lock_ != NULL);
- MutexLocker ml(thread_list_lock_);
-
- // Handle case where |thread| is head of list.
- if (thread_list_head_ == thread) {
- thread_list_head_ = thread->thread_list_next_;
- thread->thread_list_next_ = NULL;
- return;
- }
-
- Thread* current = thread_list_head_;
- Thread* previous = NULL;
-
- // Scan across list and remove |thread|.
- while (current != NULL) {
- previous = current;
- current = current->thread_list_next_;
- if (current == thread) {
- // We found |thread|, remove from list.
- previous->thread_list_next_ = current->thread_list_next_;
- thread->thread_list_next_ = NULL;
- return;
- }
- }
-
- UNREACHABLE();
-}
-
-
-bool Thread::IsThreadInList(ThreadId join_id) {
- if (join_id == OSThread::kInvalidThreadJoinId) {
- return false;
- }
- ThreadIterator it;
- while (it.HasNext()) {
- Thread* t = it.Next();
- // An address test is not sufficient because the allocator may recycle
- // the address for another Thread. Test against the thread's join id.
- if (t->join_id() == join_id) {
- return true;
- }
- }
- return false;
-}
-
-
-static void DeleteThread(void* thread) {
- delete reinterpret_cast<Thread*>(thread);
-}
-
-
-void Thread::Shutdown() {
- if (thread_list_lock_ != NULL) {
- // Delete the current thread.
- Thread* thread = Current();
- ASSERT(thread != NULL);
- delete thread;
- thread = NULL;
- SetCurrent(NULL);
-
- // Check that there are no more threads, then delete the lock.
- {
- MutexLocker ml(thread_list_lock_);
- ASSERT(thread_list_head_ == NULL);
- }
-
- // Clean up TLS.
- OSThread::DeleteThreadLocal(thread_key_);
- thread_key_ = OSThread::kUnsetThreadLocalKey;
-
- // Delete the thread list lock.
- delete thread_list_lock_;
- thread_list_lock_ = NULL;
- }
-}
-
-
Thread::~Thread() {
// We should cleanly exit any isolate before destruction.
ASSERT(isolate_ == NULL);
- // Clear |this| from all isolate's thread registry.
- ThreadPruner pruner(this);
- Isolate::VisitIsolates(&pruner);
- delete log_;
- log_ = NULL;
- RemoveThreadFromList(this);
-}
-
-
-void Thread::InitOnceBeforeIsolate() {
- ASSERT(thread_list_lock_ == NULL);
- thread_list_lock_ = new Mutex();
- ASSERT(thread_list_lock_ != NULL);
- ASSERT(thread_key_ == OSThread::kUnsetThreadLocalKey);
- thread_key_ = OSThread::CreateThreadLocal(DeleteThread);
- ASSERT(thread_key_ != OSThread::kUnsetThreadLocalKey);
- ASSERT(Thread::Current() == NULL);
- // Allocate a new Thread and postpone initialization of VM constants for
- // this first thread.
- Thread* thread = new Thread(false);
- // Verify that current thread was set.
- ASSERT(Thread::Current() == thread);
-}
-
-
-void Thread::InitOnceAfterObjectAndStubCode() {
- Thread* thread = Thread::Current();
- ASSERT(thread != NULL);
- ASSERT(thread->isolate() == Dart::vm_isolate());
- thread->InitVMConstants();
-}
-
-
-void Thread::SetCurrent(Thread* current) {
- OSThread::SetThreadLocal(thread_key_, reinterpret_cast<uword>(current));
-}
-
-
-void Thread::EnsureInit() {
- if (Thread::Current() == NULL) {
- // Allocate a new Thread.
- Thread* thread = new Thread();
- // Verify that current thread was set.
- ASSERT(Thread::Current() == thread);
- }
}
@@ -211,28 +38,32 @@
object##_handle_(NULL),
-Thread::Thread(bool init_vm_constants)
- : id_(OSThread::GetCurrentThreadId()),
- join_id_(OSThread::GetCurrentThreadJoinId()),
- trace_id_(OSThread::GetCurrentThreadTraceId()),
- thread_interrupt_disabled_(1), // Thread interrupts disabled by default.
+Thread::Thread(Isolate* isolate)
+ : BaseThread(false),
+ os_thread_(NULL),
isolate_(NULL),
heap_(NULL),
- timeline_block_(NULL),
+ zone_(NULL),
+ api_reusable_scope_(NULL),
+ api_top_scope_(NULL),
+ top_exit_frame_info_(0),
+ top_resource_(NULL),
+ long_jump_base_(NULL),
store_buffer_block_(NULL),
- log_(new class Log()),
- REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
- REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
+ no_callback_scope_depth_(0),
+#if defined(DEBUG)
+ top_handle_scope_(NULL),
+ no_handle_scope_depth_(0),
+ no_safepoint_scope_depth_(0),
+#endif
reusable_handles_(),
cha_(NULL),
deopt_id_(0),
vm_tag_(0),
pending_functions_(GrowableObjectArray::null()),
- no_callback_scope_depth_(0),
- thread_list_next_(NULL),
- name_(NULL) {
- ClearState();
-
+ REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
+ REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_SCOPE_INIT)
+ next_(NULL) {
#define DEFAULT_INIT(type_name, member_name, init_expr, default_init_value) \
member_name = default_init_value;
CACHED_CONSTANTS_LIST(DEFAULT_INIT)
@@ -248,14 +79,59 @@
LEAF_RUNTIME_ENTRY_LIST(DEFAULT_INIT)
#undef DEFAULT_INIT
- if (init_vm_constants) {
+ // We cannot initialize the VM constants here for the vm isolate thread
+ // due to boot strapping issues.
+ if ((Dart::vm_isolate() != NULL) && (isolate != Dart::vm_isolate())) {
InitVMConstants();
}
- SetCurrent(this);
- AddThreadToList(this);
}
+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());
@@ -288,12 +164,6 @@
}
-void Thread::ClearState() {
- memset(&state_, 0, sizeof(state_));
- pending_functions_ = GrowableObjectArray::null();
-}
-
-
RawGrowableObjectArray* Thread::pending_functions() {
if (pending_functions_ == GrowableObjectArray::null()) {
pending_functions_ = GrowableObjectArray::New(Heap::kOld);
@@ -302,96 +172,67 @@
}
-void Thread::Schedule(Isolate* isolate, bool bypass_safepoint) {
- State st;
- if (isolate->thread_registry()->RestoreStateTo(this, &st, bypass_safepoint)) {
- ASSERT(isolate->thread_registry()->Contains(this));
- state_ = st;
- }
-}
-
-
-void Thread::Unschedule(bool bypass_safepoint) {
- ThreadRegistry* reg = isolate_->thread_registry();
- ASSERT(reg->Contains(this));
- reg->SaveStateFrom(this, state_, bypass_safepoint);
- ClearState();
-}
-
-
void Thread::EnterIsolate(Isolate* isolate) {
- Thread* thread = Thread::Current();
- ASSERT(thread != NULL);
- ASSERT(thread->isolate() == NULL);
- ASSERT(!isolate->HasMutatorThread());
- thread->isolate_ = isolate;
+ const bool kIsMutatorThread = true;
+ const bool kDontBypassSafepoints = false;
+ ThreadRegistry* tr = isolate->thread_registry();
+ Thread* thread = tr->Schedule(
+ isolate, kIsMutatorThread, kDontBypassSafepoints);
isolate->MakeCurrentThreadMutator(thread);
thread->set_vm_tag(VMTag::kVMTagId);
ASSERT(thread->store_buffer_block_ == NULL);
thread->StoreBufferAcquire();
- ASSERT(isolate->heap() != NULL);
- thread->heap_ = isolate->heap();
- thread->Schedule(isolate);
- thread->EnableThreadInterrupts();
}
void Thread::ExitIsolate() {
Thread* thread = Thread::Current();
- // TODO(koda): Audit callers; they should know whether they're in an isolate.
- if (thread == NULL || thread->isolate() == NULL) return;
+ ASSERT(thread != NULL);
+ ASSERT(thread->IsMutatorThread());
#if defined(DEBUG)
ASSERT(!thread->IsAnyReusableHandleScopeActive());
#endif // DEBUG
- thread->DisableThreadInterrupts();
// Clear since GC will not visit the thread once it is unscheduled.
thread->ClearReusableHandles();
- Isolate* isolate = thread->isolate();
- thread->Unschedule();
- // TODO(koda): Move store_buffer_block_ into State.
thread->StoreBufferRelease();
+ Isolate* isolate = thread->isolate();
+ ASSERT(isolate != NULL);
if (isolate->is_runnable()) {
thread->set_vm_tag(VMTag::kIdleTagId);
} else {
thread->set_vm_tag(VMTag::kLoadWaitTagId);
}
+ const bool kIsMutatorThread = true;
+ const bool kDontBypassSafepoints = false;
+ ThreadRegistry* tr = isolate->thread_registry();
+ tr->Unschedule(thread, kIsMutatorThread, kDontBypassSafepoints);
isolate->ClearMutatorThread();
- thread->isolate_ = NULL;
- ASSERT(Isolate::Current() == NULL);
- thread->heap_ = NULL;
}
void Thread::EnterIsolateAsHelper(Isolate* isolate, bool bypass_safepoint) {
- Thread* thread = Thread::Current();
- ASSERT(thread != NULL);
- ASSERT(thread->isolate() == NULL);
- thread->isolate_ = isolate;
+ const bool kIsNotMutatorThread = false;
+ ThreadRegistry* tr = isolate->thread_registry();
+ Thread* thread = tr->Schedule(isolate, kIsNotMutatorThread, bypass_safepoint);
ASSERT(thread->store_buffer_block_ == NULL);
// TODO(koda): Use StoreBufferAcquire once we properly flush before Scavenge.
thread->store_buffer_block_ =
thread->isolate()->store_buffer()->PopEmptyBlock();
- ASSERT(isolate->heap() != NULL);
- thread->heap_ = isolate->heap();
- // Do not update isolate->mutator_thread, but perform sanity check:
- // this thread should not be both the main mutator and helper.
+ // This thread should not be the main mutator.
ASSERT(!thread->IsMutatorThread());
- thread->Schedule(isolate, bypass_safepoint);
- thread->EnableThreadInterrupts();
}
void Thread::ExitIsolateAsHelper(bool bypass_safepoint) {
Thread* thread = Thread::Current();
- thread->DisableThreadInterrupts();
+ ASSERT(thread != NULL);
+ ASSERT(!thread->IsMutatorThread());
+ thread->StoreBufferRelease();
Isolate* isolate = thread->isolate();
ASSERT(isolate != NULL);
- thread->Unschedule(bypass_safepoint);
- // TODO(koda): Move store_buffer_block_ into State.
- thread->StoreBufferRelease();
- thread->isolate_ = NULL;
- thread->heap_ = NULL;
- ASSERT(!thread->IsMutatorThread());
+ const bool kIsNotMutatorThread = false;
+ ThreadRegistry* tr = isolate->thread_registry();
+ tr->Unschedule(thread, kIsNotMutatorThread, bypass_safepoint);
}
@@ -459,23 +300,6 @@
}
-CHA* Thread::cha() const {
- ASSERT(isolate_ != NULL);
- return cha_;
-}
-
-
-void Thread::set_cha(CHA* value) {
- ASSERT(isolate_ != NULL);
- cha_ = value;
-}
-
-
-Log* Thread::log() const {
- return log_;
-}
-
-
template<class C>
C* Thread::AllocateReusableHandle() {
C* handle = reinterpret_cast<C*>(reusable_handles_.AllocateScopedHandle());
@@ -498,38 +322,18 @@
// Visit objects in thread specific handles area.
reusable_handles_.VisitObjectPointers(visitor);
+ // Visit the pending functions.
if (pending_functions_ != GrowableObjectArray::null()) {
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&pending_functions_));
}
-}
-
-void Thread::DisableThreadInterrupts() {
- ASSERT(Thread::Current() == this);
- AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_);
-}
-
-
-void Thread::EnableThreadInterrupts() {
- ASSERT(Thread::Current() == this);
- uintptr_t old =
- AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
- if (old == 1) {
- // We just decremented from 1 to 0.
- // Make sure the thread interrupter is awake.
- ThreadInterrupter::WakeUp();
+ // Visit the api local scope as it has all the api local handles.
+ ApiLocalScope* scope = api_top_scope_;
+ while (scope != NULL) {
+ scope->local_handles()->VisitObjectPointers(visitor);
+ scope = scope->previous();
}
- if (old == 0) {
- // We just decremented from 0, this means we've got a mismatched pair
- // of calls to EnableThreadInterrupts and DisableThreadInterrupts.
- FATAL("Invalid call to Thread::EnableThreadInterrupts()");
- }
-}
-
-
-bool Thread::ThreadInterruptsEnabled() {
- return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0;
}
@@ -585,48 +389,69 @@
}
-ThreadIterator::ThreadIterator() {
- ASSERT(Thread::thread_list_lock_ != NULL);
- // Lock the thread list while iterating.
- Thread::thread_list_lock_->Lock();
- next_ = Thread::thread_list_head_;
+bool Thread::IsValidLocalHandle(Dart_Handle object) const {
+ ApiLocalScope* scope = api_top_scope_;
+ while (scope != NULL) {
+ if (scope->local_handles()->IsValidHandle(object)) {
+ return true;
+ }
+ scope = scope->previous();
+ }
+ return false;
}
-ThreadIterator::~ThreadIterator() {
- ASSERT(Thread::thread_list_lock_ != NULL);
- // Unlock the thread list when done.
- Thread::thread_list_lock_->Unlock();
+int Thread::CountLocalHandles() const {
+ int total = 0;
+ ApiLocalScope* scope = api_top_scope_;
+ while (scope != NULL) {
+ total += scope->local_handles()->CountHandles();
+ scope = scope->previous();
+ }
+ return total;
}
-bool ThreadIterator::HasNext() const {
- ASSERT(Thread::thread_list_lock_ != NULL);
- ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread());
- return next_ != NULL;
+int Thread::ZoneSizeInBytes() const {
+ int total = 0;
+ ApiLocalScope* scope = api_top_scope_;
+ while (scope != NULL) {
+ total += scope->zone()->SizeInBytes();
+ scope = scope->previous();
+ }
+ return total;
}
-Thread* ThreadIterator::Next() {
- ASSERT(Thread::thread_list_lock_ != NULL);
- ASSERT(Thread::thread_list_lock_->IsOwnedByCurrentThread());
- Thread* current = next_;
- next_ = next_->thread_list_next_;
- return current;
+void Thread::UnwindScopes(uword stack_marker) {
+ // Unwind all scopes using the same stack_marker, i.e. all scopes allocated
+ // under the same top_exit_frame_info.
+ ApiLocalScope* scope = api_top_scope_;
+ while (scope != NULL &&
+ scope->stack_marker() != 0 &&
+ scope->stack_marker() == stack_marker) {
+ api_top_scope_ = scope->previous();
+ delete scope;
+ scope = api_top_scope_;
+ }
}
DisableThreadInterruptsScope::DisableThreadInterruptsScope(Thread* thread)
: StackResource(thread) {
if (thread != NULL) {
- thread->DisableThreadInterrupts();
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ os_thread->DisableThreadInterrupts();
}
}
DisableThreadInterruptsScope::~DisableThreadInterruptsScope() {
if (thread() != NULL) {
- thread()->EnableThreadInterrupts();
+ OSThread* os_thread = thread()->os_thread();
+ ASSERT(os_thread != NULL);
+ os_thread->EnableThreadInterrupts();
}
}
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index d4a3ea1..15483cb 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -5,6 +5,7 @@
#ifndef VM_THREAD_H_
#define VM_THREAD_H_
+#include "include/dart_api.h"
#include "vm/globals.h"
#include "vm/handles.h"
#include "vm/os_thread.h"
@@ -14,6 +15,7 @@
namespace dart {
class AbstractType;
+class ApiLocalScope;
class Array;
class CHA;
class Class;
@@ -28,9 +30,9 @@
class Instance;
class Isolate;
class Library;
-class Log;
class LongJumpScope;
class Object;
+class OSThread;
class PcDescriptors;
class RawBool;
class RawObject;
@@ -40,7 +42,6 @@
class RuntimeEntry;
class StackResource;
class String;
-class TimelineEventBlock;
class TypeArguments;
class TypeParameter;
class Zone;
@@ -78,7 +79,6 @@
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) \
@@ -86,27 +86,41 @@
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
// automatically when the underlying OS thread exits. NOTE: On Windows, CleanUp
// must currently be called manually (issue 23474).
-class Thread {
+class Thread : public BaseThread {
public:
+ ~Thread();
+
// The currently executing thread, or NULL if not yet initialized.
static Thread* Current() {
- return reinterpret_cast<Thread*>(OSThread::GetThreadLocal(thread_key_));
+ BaseThread* thread = OSThread::GetCurrentTLS();
+ if (thread == NULL || thread->is_os_thread()) {
+ return NULL;
+ }
+ return reinterpret_cast<Thread*>(thread);
}
- // Initializes the current thread as a VM thread, if not already done.
- static void EnsureInit();
-
// Makes the current thread enter 'isolate'.
static void EnterIsolate(Isolate* isolate);
// Makes the current thread exit its isolate.
@@ -125,16 +139,26 @@
// TODO(koda): Always run GC in separate thread.
static void PrepareForGC();
- // Called at VM startup.
- static void InitOnceBeforeIsolate();
- static void InitOnceAfterObjectAndStubCode();
-
- // Called at VM shutdown
- static void Shutdown();
- ~Thread();
+ // OSThread corresponding to this thread.
+ OSThread* os_thread() const { return os_thread_; }
+ void set_os_thread(OSThread* os_thread) {
+ os_thread_ = os_thread;
+ }
// The topmost zone used for allocation in this thread.
- Zone* zone() const { return state_.zone; }
+ Zone* zone() const { return zone_; }
+
+ // The reusable api local scope for this thread.
+ ApiLocalScope* api_reusable_scope() const { return api_reusable_scope_; }
+ void set_api_reusable_scope(ApiLocalScope* value) {
+ ASSERT(value == NULL || api_reusable_scope_ == NULL);
+ api_reusable_scope_ = value;
+ }
+
+ // The api local scope for this thread, this where all local handles
+ // are allocated.
+ ApiLocalScope* api_top_scope() const { return api_top_scope_; }
+ void set_api_top_scope(ApiLocalScope* value) { api_top_scope_ = value; }
// The isolate that this thread is operating on, or NULL if none.
Isolate* isolate() const { return isolate_; }
@@ -150,8 +174,15 @@
bool HasExitedDartCode() const;
// The (topmost) CHA for the compilation in this thread.
- CHA* cha() const;
- void set_cha(CHA* value);
+ CHA* cha() const {
+ ASSERT(isolate_ != NULL);
+ return cha_;
+ }
+
+ void set_cha(CHA* value) {
+ ASSERT(isolate_ != NULL);
+ cha_ = value;
+ }
int32_t no_callback_scope_depth() const {
return no_callback_scope_depth_;
@@ -179,26 +210,28 @@
return OFFSET_OF(Thread, store_buffer_block_);
}
- uword top_exit_frame_info() const { return state_.top_exit_frame_info; }
+ uword top_exit_frame_info() const { return top_exit_frame_info_; }
static intptr_t top_exit_frame_info_offset() {
- return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_exit_frame_info);
+ return OFFSET_OF(Thread, top_exit_frame_info_);
}
- StackResource* top_resource() const { return state_.top_resource; }
+ StackResource* top_resource() const { return top_resource_; }
void set_top_resource(StackResource* value) {
- state_.top_resource = value;
+ top_resource_ = value;
}
static intptr_t top_resource_offset() {
- return OFFSET_OF(Thread, state_) + OFFSET_OF(State, top_resource);
+ return OFFSET_OF(Thread, top_resource_);
}
+ // Heap of the isolate that this thread is operating on.
+ Heap* heap() const { return heap_; }
static intptr_t heap_offset() {
return OFFSET_OF(Thread, heap_);
}
int32_t no_handle_scope_depth() const {
#if defined(DEBUG)
- return state_.no_handle_scope_depth;
+ return no_handle_scope_depth_;
#else
return 0;
#endif
@@ -206,21 +239,21 @@
void IncrementNoHandleScopeDepth() {
#if defined(DEBUG)
- ASSERT(state_.no_handle_scope_depth < INT_MAX);
- state_.no_handle_scope_depth += 1;
+ ASSERT(no_handle_scope_depth_ < INT_MAX);
+ no_handle_scope_depth_ += 1;
#endif
}
void DecrementNoHandleScopeDepth() {
#if defined(DEBUG)
- ASSERT(state_.no_handle_scope_depth > 0);
- state_.no_handle_scope_depth -= 1;
+ ASSERT(no_handle_scope_depth_ > 0);
+ no_handle_scope_depth_ -= 1;
#endif
}
HandleScope* top_handle_scope() const {
#if defined(DEBUG)
- return state_.top_handle_scope;
+ return top_handle_scope_;
#else
return 0;
#endif
@@ -228,13 +261,13 @@
void set_top_handle_scope(HandleScope* handle_scope) {
#if defined(DEBUG)
- state_.top_handle_scope = handle_scope;
+ top_handle_scope_ = handle_scope;
#endif
}
int32_t no_safepoint_scope_depth() const {
#if defined(DEBUG)
- return state_.no_safepoint_scope_depth;
+ return no_safepoint_scope_depth_;
#else
return 0;
#endif
@@ -242,32 +275,18 @@
void IncrementNoSafepointScopeDepth() {
#if defined(DEBUG)
- ASSERT(state_.no_safepoint_scope_depth < INT_MAX);
- state_.no_safepoint_scope_depth += 1;
+ ASSERT(no_safepoint_scope_depth_ < INT_MAX);
+ no_safepoint_scope_depth_ += 1;
#endif
}
void DecrementNoSafepointScopeDepth() {
#if defined(DEBUG)
- ASSERT(state_.no_safepoint_scope_depth > 0);
- state_.no_safepoint_scope_depth -= 1;
+ ASSERT(no_safepoint_scope_depth_ > 0);
+ no_safepoint_scope_depth_ -= 1;
#endif
}
- // Collection of isolate-specific state of a thread that is saved/restored
- // on isolate exit/re-entry.
- struct State {
- Zone* zone;
- uword top_exit_frame_info;
- StackResource* top_resource;
- LongJumpScope* long_jump_base;
-#if defined(DEBUG)
- HandleScope* top_handle_scope;
- intptr_t no_handle_scope_depth;
- int32_t no_safepoint_scope_depth;
-#endif
- };
-
#define DEFINE_OFFSET_METHOD(type_name, member_name, expr, default_init_value) \
static intptr_t member_name##offset() { \
return OFFSET_OF(Thread, member_name); \
@@ -294,22 +313,6 @@
static bool ObjectAtOffset(intptr_t offset, Object* object);
static intptr_t OffsetFromThread(const RuntimeEntry* runtime_entry);
- Mutex* timeline_block_lock() {
- return &timeline_block_lock_;
- }
-
- // Only safe to access when holding |timeline_block_lock_|.
- TimelineEventBlock* timeline_block() const {
- return timeline_block_;
- }
-
- // Only safe to access when holding |timeline_block_lock_|.
- void set_timeline_block(TimelineEventBlock* block) {
- timeline_block_ = block;
- }
-
- class Log* log() const;
-
static const intptr_t kNoDeoptId = -1;
static const intptr_t kDeoptIdStep = 2;
static const intptr_t kDeoptIdBeforeOffset = 0;
@@ -339,9 +342,9 @@
return (deopt_id % kDeoptIdStep) == kDeoptIdAfterOffset;
}
- LongJumpScope* long_jump_base() const { return state_.long_jump_base; }
+ LongJumpScope* long_jump_base() const { return long_jump_base_; }
void set_long_jump_base(LongJumpScope* value) {
- state_.long_jump_base = value;
+ long_jump_base_ = value;
}
uword vm_tag() const {
@@ -354,36 +357,6 @@
return OFFSET_OF(Thread, vm_tag_);
}
- ThreadId id() const {
- ASSERT(id_ != OSThread::kInvalidThreadId);
- return id_;
- }
-
- ThreadId join_id() const {
- ASSERT(join_id_ != OSThread::kInvalidThreadJoinId);
- return join_id_;
- }
-
- ThreadId trace_id() const {
- ASSERT(trace_id_ != OSThread::kInvalidThreadJoinId);
- return trace_id_;
- }
-
- const char* name() const {
- return name_;
- }
-
- void set_name(const char* name) {
- ASSERT(Thread::Current() == this);
- ASSERT(name_ == NULL);
- name_ = name;
- }
-
- // Used to temporarily disable or enable thread interrupts.
- void DisableThreadInterrupts();
- void EnableThreadInterrupts();
- bool ThreadInterruptsEnabled();
-
#if defined(DEBUG)
#define REUSABLE_HANDLE_SCOPE_ACCESSORS(object) \
void set_reusable_##object##_handle_scope_active(bool value) { \
@@ -415,26 +388,44 @@
RawGrowableObjectArray* pending_functions();
+ // Visit all object pointers.
void VisitObjectPointers(ObjectPointerVisitor* visitor);
- static bool IsThreadInList(ThreadId join_id);
+ bool IsValidLocalHandle(Dart_Handle object) const;
+ int CountLocalHandles() const;
+ int ZoneSizeInBytes() const;
+ void UnwindScopes(uword stack_marker);
+
+ void InitVMConstants();
private:
template<class T> T* AllocateReusableHandle();
- static ThreadLocalKey thread_key_;
-
- const ThreadId id_;
- const ThreadId join_id_;
- const ThreadId trace_id_;
- uintptr_t thread_interrupt_disabled_;
+ OSThread* os_thread_;
Isolate* isolate_;
Heap* heap_;
- State state_;
- Mutex timeline_block_lock_;
- TimelineEventBlock* timeline_block_;
+ Zone* zone_;
+ ApiLocalScope* api_reusable_scope_;
+ ApiLocalScope* api_top_scope_;
+ uword top_exit_frame_info_;
+ StackResource* top_resource_;
+ LongJumpScope* long_jump_base_;
StoreBufferBlock* store_buffer_block_;
- class Log* log_;
+ int32_t no_callback_scope_depth_;
+#if defined(DEBUG)
+ HandleScope* top_handle_scope_;
+ intptr_t no_handle_scope_depth_;
+ int32_t no_safepoint_scope_depth_;
+#endif
+ VMHandles reusable_handles_;
+
+ // Compiler state:
+ CHA* cha_;
+ intptr_t deopt_id_; // Compilation specific counter.
+ uword vm_tag_;
+ RawGrowableObjectArray* pending_functions_;
+
+ // State that is cached in the TLS for fast access in generated code.
#define DECLARE_MEMBERS(type_name, member_name, expr, default_init_value) \
type_name member_name;
CACHED_CONSTANTS_LIST(DECLARE_MEMBERS)
@@ -463,50 +454,25 @@
#undef REUSABLE_HANDLE_SCOPE_VARIABLE
#endif // defined(DEBUG)
- VMHandles reusable_handles_;
+ Thread* next_; // Used to chain the thread structures in an isolate.
- // Compiler state:
- CHA* cha_;
- intptr_t deopt_id_; // Compilation specific counter.
- uword vm_tag_;
- RawGrowableObjectArray* pending_functions_;
-
- int32_t no_callback_scope_depth_;
-
- // All |Thread|s are registered in the thread list.
- Thread* thread_list_next_;
-
- // A name for this thread.
- const char* name_;
-
- static Thread* thread_list_head_;
- static Mutex* thread_list_lock_;
-
- static void AddThreadToList(Thread* thread);
- static void RemoveThreadFromList(Thread* thread);
-
- explicit Thread(bool init_vm_constants = true);
-
- void InitVMConstants();
-
- void ClearState();
+ explicit Thread(Isolate* isolate);
void StoreBufferRelease(
StoreBuffer::ThresholdPolicy policy = StoreBuffer::kCheckThreshold);
void StoreBufferAcquire();
void set_zone(Zone* zone) {
- state_.zone = zone;
+ zone_ = zone;
}
void set_top_exit_frame_info(uword top_exit_frame_info) {
- state_.top_exit_frame_info = top_exit_frame_info;
+ top_exit_frame_info_ = top_exit_frame_info;
}
- static void SetCurrent(Thread* current);
-
- void Schedule(Isolate* isolate, bool bypass_safepoint = false);
- void Unschedule(bool bypass_safepoint = false);
+ static void SetCurrent(Thread* current) {
+ OSThread::SetCurrentTLS(reinterpret_cast<uword>(current));
+ }
#define REUSABLE_FRIEND_DECLARATION(name) \
friend class Reusable##name##HandleScope;
@@ -517,31 +483,12 @@
friend class Isolate;
friend class Simulator;
friend class StackZone;
- friend class ThreadIterator;
- friend class ThreadIteratorTestHelper;
friend class ThreadRegistry;
DISALLOW_COPY_AND_ASSIGN(Thread);
};
-// Note that this takes the thread list lock, prohibiting threads from coming
-// on- or off-line.
-class ThreadIterator : public ValueObject {
- public:
- ThreadIterator();
- ~ThreadIterator();
-
- // Returns false when there are no more threads left.
- bool HasNext() const;
-
- // Returns the current thread and moves forward.
- Thread* Next();
-
- private:
- Thread* next_;
-};
-
#if defined(TARGET_OS_WINDOWS)
// Clears the state of the current thread and frees the allocation.
void WindowsThreadCleanUp();
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
index 8a8af04..920baf6 100644
--- a/runtime/vm/thread_interrupter.cc
+++ b/runtime/vm/thread_interrupter.cc
@@ -75,7 +75,7 @@
ASSERT(interrupter_thread_id_ == OSThread::kInvalidThreadJoinId);
{
MonitorLocker startup_ml(monitor_);
- OSThread::Start(ThreadMain, 0);
+ OSThread::Start("ThreadInterrupter", ThreadMain, 0);
while (!thread_running_) {
startup_ml.Wait();
}
@@ -153,7 +153,9 @@
{
// Signal to main thread we are ready.
MonitorLocker startup_ml(monitor_);
- interrupter_thread_id_ = OSThread::GetCurrentThreadJoinId();
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ interrupter_thread_id_ = os_thread->join_id();
thread_running_ = true;
startup_ml.Notify();
}
@@ -182,9 +184,9 @@
monitor_->Exit();
{
- ThreadIterator it;
+ OSThreadIterator it;
while (it.HasNext()) {
- Thread* thread = it.Next();
+ OSThread* thread = it.Next();
if (thread->ThreadInterruptsEnabled()) {
interrupted_thread_count++;
InterruptThread(thread);
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
index 5357615..82e0474 100644
--- a/runtime/vm/thread_interrupter.h
+++ b/runtime/vm/thread_interrupter.h
@@ -35,7 +35,7 @@
static void WakeUp();
// Interrupt a thread.
- static void InterruptThread(Thread* thread);
+ static void InterruptThread(OSThread* thread);
private:
static const intptr_t kMaxThreads = 4096;
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
index 1c780ba..6656775 100644
--- a/runtime/vm/thread_interrupter_android.cc
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -44,7 +44,7 @@
};
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter interrupting %p\n",
reinterpret_cast<void*>(thread->id()));
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
index 2cb0f55..28ec681 100644
--- a/runtime/vm/thread_interrupter_linux.cc
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -43,7 +43,7 @@
};
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter interrupting %p\n",
reinterpret_cast<void*>(thread->id()));
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
index c53ae13..a25c3c2 100644
--- a/runtime/vm/thread_interrupter_macos.cc
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -43,7 +43,7 @@
};
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter interrupting %p\n", thread->id());
}
@@ -64,4 +64,3 @@
} // namespace dart
#endif // defined(TARGET_OS_MACOS)
-
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
index 4231d1e..ac613c1 100644
--- a/runtime/vm/thread_interrupter_win.cc
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -52,19 +52,19 @@
}
- static void Interrupt(Thread* thread) {
- ASSERT(!OSThread::Compare(GetCurrentThreadId(), thread->id()));
+ static void Interrupt(OSThread* os_thread) {
+ ASSERT(!OSThread::Compare(GetCurrentThreadId(), os_thread->id()));
HANDLE handle = OpenThread(THREAD_GET_CONTEXT |
THREAD_QUERY_INFORMATION |
THREAD_SUSPEND_RESUME,
false,
- thread->id());
+ os_thread->id());
ASSERT(handle != NULL);
DWORD result = SuspendThread(handle);
if (result == kThreadError) {
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter failed to suspend thread %p\n",
- reinterpret_cast<void*>(thread->id()));
+ reinterpret_cast<void*>(os_thread->id()));
}
CloseHandle(handle);
return;
@@ -75,19 +75,25 @@
ResumeThread(handle);
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter failed to get registers for %p\n",
- reinterpret_cast<void*>(thread->id()));
+ reinterpret_cast<void*>(os_thread->id()));
}
CloseHandle(handle);
return;
}
- Profiler::SampleThread(thread, its);
+ // Currently we sample only threads that are associated
+ // with an isolate. It is safe to call 'os_thread->thread()'
+ // here as the thread which is being queried is suspended.
+ Thread* thread = os_thread->thread();
+ if (thread != NULL) {
+ Profiler::SampleThread(thread, its);
+ }
ResumeThread(handle);
CloseHandle(handle);
}
};
-void ThreadInterrupter::InterruptThread(Thread* thread) {
+void ThreadInterrupter::InterruptThread(OSThread* thread) {
if (FLAG_trace_thread_interrupter) {
OS::Print("ThreadInterrupter suspending %p\n",
reinterpret_cast<void*>(thread->id()));
@@ -113,4 +119,3 @@
} // namespace dart
#endif // defined(TARGET_OS_WINDOWS)
-
diff --git a/runtime/vm/thread_pool.cc b/runtime/vm/thread_pool.cc
index d5472a6..86d2f60 100644
--- a/runtime/vm/thread_pool.cc
+++ b/runtime/vm/thread_pool.cc
@@ -101,7 +101,9 @@
// First tell all the workers to shut down.
Worker* current = saved;
- ThreadId id = OSThread::GetCurrentThreadId();
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ ThreadId id = os_thread->id();
while (current != NULL) {
Worker* next = current->all_next_;
ThreadId currentId = current->id();
@@ -245,7 +247,9 @@
// The thread for worker will exit. Add its ThreadId to the join_list_
// so that we can join on it at the next opportunity.
- JoinList::AddLocked(OSThread::GetCurrentThreadJoinId(), &join_list_);
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ JoinList::AddLocked(os_thread->join_id(), &join_list_);
count_stopped_++;
count_idle_--;
return true;
@@ -333,7 +337,9 @@
ASSERT(task_ != NULL);
}
#endif
- int result = OSThread::Start(&Worker::Main, reinterpret_cast<uword>(this));
+ int result = OSThread::Start("Dart ThreadPool Worker",
+ &Worker::Main,
+ reinterpret_cast<uword>(this));
if (result != 0) {
FATAL1("Could not start worker thread: result = %d.", result);
}
@@ -417,12 +423,11 @@
// static
void ThreadPool::Worker::Main(uword args) {
- Thread::EnsureInit();
- Thread* thread = Thread::Current();
- thread->set_name("Dart ThreadPool Worker");
Worker* worker = reinterpret_cast<Worker*>(args);
- ThreadId id = OSThread::GetCurrentThreadId();
- ThreadJoinId join_id = OSThread::GetCurrentThreadJoinId();
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ ThreadId id = os_thread->id();
+ ThreadJoinId join_id = os_thread->join_id();
ThreadPool* pool;
{
diff --git a/runtime/vm/thread_registry.cc b/runtime/vm/thread_registry.cc
index f0f80e3..0d36e0d 100644
--- a/runtime/vm/thread_registry.cc
+++ b/runtime/vm/thread_registry.cc
@@ -10,6 +10,24 @@
namespace dart {
ThreadRegistry::~ThreadRegistry() {
+ // Go over the free thread list and delete the thread objects.
+ {
+ MonitorLocker ml(monitor_);
+ // At this point the mutator thread should be the only thread
+ // in the active list, delete it.
+ ASSERT(active_list_->next_ == NULL);
+ ASSERT(active_list_ == mutator_thread_);
+ delete mutator_thread_;
+ active_list_ = NULL;
+ mutator_thread_ = NULL;
+ // Now delete all the threads in the free list.
+ while (free_list_ != NULL) {
+ Thread* thread = free_list_;
+ free_list_ = thread->next_;
+ delete thread;
+ }
+ }
+
// Delete monitor.
delete monitor_;
}
@@ -50,67 +68,125 @@
}
-void ThreadRegistry::PruneThread(Thread* thread) {
+Thread* ThreadRegistry::Schedule(Isolate* isolate,
+ bool is_mutator,
+ bool bypass_safepoint) {
MonitorLocker ml(monitor_);
- intptr_t length = entries_.length();
- if (length == 0) {
- return;
+ // Wait for any rendezvous in progress.
+ while (!bypass_safepoint && in_rendezvous_) {
+ ml.Wait(Monitor::kNoTimeout);
}
- intptr_t found_index = -1;
- for (intptr_t index = 0; index < length; index++) {
- if (entries_.At(index).thread == thread) {
- found_index = index;
- break;
+ Thread* thread = NULL;
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ ASSERT(isolate->heap() != NULL);
+ if (is_mutator) {
+ if (mutator_thread_ == NULL) {
+ mutator_thread_ = GetThreadFromFreelist(isolate);
+ }
+ thread = mutator_thread_;
+ } else {
+ thread = GetThreadFromFreelist(isolate);
+ ASSERT(thread->api_top_scope() == NULL);
+ }
+ thread->isolate_ = isolate;
+ thread->heap_ = isolate->heap();
+ thread->set_os_thread(os_thread);
+ os_thread->set_thread(thread);
+ Thread::SetCurrent(thread);
+ os_thread->EnableThreadInterrupts();
+ return thread;
+}
+
+
+void ThreadRegistry::Unschedule(Thread* thread,
+ bool is_mutator,
+ bool bypass_safepoint) {
+ MonitorLocker ml(monitor_);
+ 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);
+ if (!is_mutator) {
+ ASSERT(thread->api_top_scope() == NULL);
+ ReturnThreadToFreelist(thread);
+ }
+ if (!bypass_safepoint && in_rendezvous_) {
+ // Don't wait for this thread.
+ ASSERT(remaining_ > 0);
+ if (--remaining_ == 0) {
+ ml.NotifyAll();
}
}
- if (found_index < 0) {
- return;
- }
- entries_.RemoveAt(found_index);
}
-ThreadRegistry::EntryIterator::EntryIterator(ThreadRegistry* registry)
- : index_(0),
- registry_(NULL) {
- Reset(registry);
-}
-
-
-ThreadRegistry::EntryIterator::~EntryIterator() {
- Reset(NULL);
-}
-
-
-void ThreadRegistry::EntryIterator::Reset(ThreadRegistry* registry) {
- // Reset index.
- index_ = 0;
-
- // Unlock old registry.
- if (registry_ != NULL) {
- registry_->monitor_->Exit();
- }
-
- registry_ = registry;
-
- // Lock new registry.
- if (registry_ != NULL) {
- registry_->monitor_->Enter();
+void ThreadRegistry::VisitObjectPointers(ObjectPointerVisitor* visitor,
+ bool validate_frames) {
+ MonitorLocker ml(monitor_);
+ Thread* thread = active_list_;
+ while (thread != NULL) {
+ if (thread->zone() != NULL) {
+ thread->zone()->VisitObjectPointers(visitor);
+ }
+ thread->VisitObjectPointers(visitor);
+ // Iterate over all the stack frames and visit objects on the stack.
+ StackFrameIterator frames_iterator(thread->top_exit_frame_info(),
+ validate_frames);
+ StackFrame* frame = frames_iterator.NextFrame();
+ while (frame != NULL) {
+ frame->VisitObjectPointers(visitor);
+ frame = frames_iterator.NextFrame();
+ }
+ thread = thread->next_;
}
}
-bool ThreadRegistry::EntryIterator::HasNext() const {
- if (registry_ == NULL) {
- return false;
+Thread* ThreadRegistry::GetThreadFromFreelist(Isolate* isolate) {
+ ASSERT(monitor_->IsOwnedByCurrentThread());
+ Thread* thread = NULL;
+ // Get thread structure from free list or create a new one.
+ if (free_list_ == NULL) {
+ thread = new Thread(isolate);
+ } else {
+ thread = free_list_;
+ free_list_ = thread->next_;
}
- return index_ < registry_->entries_.length();
+ // Add thread to active list.
+ thread->next_ = active_list_;
+ active_list_ = thread;
+ return thread;
}
-
-const ThreadRegistry::Entry& ThreadRegistry::EntryIterator::Next() {
- ASSERT(HasNext());
- return registry_->entries_.At(index_++);
+void ThreadRegistry::ReturnThreadToFreelist(Thread* thread) {
+ ASSERT(thread != NULL);
+ ASSERT(thread->os_thread_ == NULL);
+ ASSERT(thread->isolate_ == NULL);
+ ASSERT(thread->heap_ == NULL);
+ ASSERT(monitor_->IsOwnedByCurrentThread());
+ // First remove the thread from the active list.
+ Thread* prev = NULL;
+ Thread* current = active_list_;
+ while (current != NULL) {
+ if (current == thread) {
+ if (prev == NULL) {
+ active_list_ = current->next_;
+ } else {
+ prev->next_ = current->next_;
+ }
+ break;
+ }
+ prev = current;
+ current = current->next_;
+ }
+ // Now add thread to the free list.
+ thread->next_ = free_list_;
+ free_list_ = thread;
}
@@ -142,11 +218,10 @@
intptr_t ThreadRegistry::CountScheduledLocked() {
intptr_t count = 0;
- for (int i = 0; i < entries_.length(); ++i) {
- const Entry& entry = entries_[i];
- if (entry.scheduled) {
- ++count;
- }
+ Thread* current = active_list_;
+ while (current != NULL) {
+ ++count;
+ current = current->next_;
}
return count;
}
diff --git a/runtime/vm/thread_registry.h b/runtime/vm/thread_registry.h
index b78a761..f077c51 100644
--- a/runtime/vm/thread_registry.h
+++ b/runtime/vm/thread_registry.h
@@ -19,13 +19,17 @@
public:
ThreadRegistry()
: monitor_(new Monitor()),
- entries_(),
+ active_list_(NULL),
+ free_list_(NULL),
+ mutator_thread_(NULL),
in_rendezvous_(false),
remaining_(0),
round_(0) {}
~ThreadRegistry();
+ Thread* active_list() const { return active_list_; }
+
// Bring all threads in this isolate to a safepoint. The caller is
// expected to be implicitly at a safepoint. The threads will wait
// until ResumeAllThreads is called. First participates in any
@@ -49,146 +53,13 @@
}
bool AtSafepoint() const { return in_rendezvous_; }
-
- bool RestoreStateTo(Thread* thread, Thread::State* state,
- bool bypass_safepoint) {
- MonitorLocker ml(monitor_);
- // Wait for any rendezvous in progress.
- while (!bypass_safepoint && in_rendezvous_) {
- ml.Wait(Monitor::kNoTimeout);
- }
- Entry* entry = FindEntry(thread);
- if (entry != NULL) {
- Thread::State st = entry->state;
- // TODO(koda): Support same thread re-entering same isolate with
- // Dart frames in between. For now, just assert it doesn't happen.
- if (st.top_exit_frame_info != thread->top_exit_frame_info()) {
- ASSERT(thread->top_exit_frame_info() == 0 ||
- thread->top_exit_frame_info() > st.top_exit_frame_info);
- }
- ASSERT(!entry->scheduled);
- entry->scheduled = true;
-#if defined(DEBUG)
- // State field is not in use, so zap it.
- memset(&entry->state, 0xda, sizeof(entry->state));
-#endif
- *state = st;
- return true;
- }
- Entry new_entry;
- new_entry.thread = thread;
- new_entry.scheduled = true;
-#if defined(DEBUG)
- // State field is not in use, so zap it.
- memset(&new_entry.state, 0xda, sizeof(new_entry.state));
-#endif
- entries_.Add(new_entry);
- return false;
- }
-
- void SaveStateFrom(Thread* thread, const Thread::State& state,
- bool bypass_safepoint) {
- MonitorLocker ml(monitor_);
- Entry* entry = FindEntry(thread);
- ASSERT(entry != NULL);
- ASSERT(entry->scheduled);
- entry->scheduled = false;
- entry->state = state;
- if (!bypass_safepoint && in_rendezvous_) {
- // Don't wait for this thread.
- ASSERT(remaining_ > 0);
- if (--remaining_ == 0) {
- ml.NotifyAll();
- }
- }
- }
-
- bool Contains(Thread* thread) {
- MonitorLocker ml(monitor_);
- return (FindEntry(thread) != NULL);
- }
-
- void CheckNotScheduled(Isolate* isolate) {
- MonitorLocker ml(monitor_);
- for (int i = 0; i < entries_.length(); ++i) {
- const Entry& entry = entries_[i];
- if (entry.scheduled) {
- FATAL3("Isolate %p still scheduled on %p (whose isolate_ is %p)\n",
- isolate,
- entry.thread,
- entry.thread->isolate());
- }
- }
- }
-
- void VisitObjectPointers(ObjectPointerVisitor* visitor,
- bool validate_frames) {
- MonitorLocker ml(monitor_);
- for (int i = 0; i < entries_.length(); ++i) {
- const Entry& entry = entries_[i];
- const Thread::State& state =
- entry.scheduled ? entry.thread->state_ : entry.state;
- if (state.zone != NULL) {
- state.zone->VisitObjectPointers(visitor);
- }
- if (entry.scheduled) {
- ASSERT(entry.thread != NULL);
- entry.thread->VisitObjectPointers(visitor);
- }
- // Iterate over all the stack frames and visit objects on the stack.
- StackFrameIterator frames_iterator(state.top_exit_frame_info,
- validate_frames);
- StackFrame* frame = frames_iterator.NextFrame();
- while (frame != NULL) {
- frame->VisitObjectPointers(visitor);
- frame = frames_iterator.NextFrame();
- }
- }
- }
-
- void PruneThread(Thread* thread);
-
- void ReclaimTimelineBlocks();
-
- struct Entry {
- // NOTE: |thread| is deleted automatically when the thread exits.
- // In other words, it is not safe to dereference |thread| unless you are on
- // the thread itself.
- Thread* thread;
- bool scheduled;
- Thread::State state;
- };
-
- class EntryIterator {
- public:
- explicit EntryIterator(ThreadRegistry* registry);
- ~EntryIterator();
-
- // Returns false when there are no more entries.
- bool HasNext() const;
-
- // Returns the next entry and moves forward.
- const Entry& Next();
-
- private:
- void Reset(ThreadRegistry* registry);
-
- intptr_t index_;
- ThreadRegistry* registry_;
- };
+ Thread* Schedule(Isolate* isolate, bool is_mutator, bool bypass_safepoint);
+ void Unschedule(Thread* thread, bool is_mutator, bool bypass_safepoint);
+ void VisitObjectPointers(ObjectPointerVisitor* visitor, bool validate_frames);
private:
- // Returns Entry corresponding to thread in registry or NULL.
- // Note: Lock should be taken before this function is called.
- // TODO(koda): Add method Monitor::IsOwnedByCurrentThread.
- Entry* FindEntry(Thread* thread) {
- for (int i = 0; i < entries_.length(); ++i) {
- if (entries_[i].thread == thread) {
- return &entries_[i];
- }
- }
- return NULL;
- }
+ Thread* GetThreadFromFreelist(Isolate* isolate);
+ void ReturnThreadToFreelist(Thread* thread);
// Note: Lock should be taken before this function is called.
void CheckSafepointLocked();
@@ -198,7 +69,22 @@
intptr_t CountScheduledLocked();
Monitor* monitor_; // All access is synchronized through this monitor.
- MallocGrowableArray<Entry> entries_;
+ Thread* active_list_; // List of active threads in the isolate.
+ Thread* free_list_; // Free list of Thread objects that can be reused.
+ // TODO(asiva): Currently we treat a mutator thread as a special thread
+ // and always schedule execution of Dart code on the same mutator thread
+ // object. The ApiLocalScope has been made thread specific but we still
+ // have scenarios where we do a temporary exit of an Isolate with live
+ // zones/handles in the the API scope :
+ // - Dart_RunLoop()
+ // - IsolateSaver in Dart_NewNativePort
+ // - Isolate spawn (function/uri) under FLAG_i_like_slow_isolate_spawn
+ // We probably need a mechanism to return to the specific thread only
+ // for these specific cases. We should also determine if the embedder
+ // should allow exiting an isolate with live state in zones/handles in
+ // which case a new API for returning to the specific thread needs to be
+ // added.
+ Thread* mutator_thread_;
// Safepoint rendezvous state.
bool in_rendezvous_; // A safepoint rendezvous request is in progress.
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 7eb5849..ec998f8 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -38,7 +38,7 @@
// This unit test case needs a running isolate.
Dart_CreateIsolate(
NULL, NULL, bin::isolate_snapshot_buffer, NULL, NULL, NULL);
- Thread* thread = Thread::Current();
+ OSThread* thread = OSThread::Current();
// Thread interrupter interferes with this test, disable interrupts.
thread->DisableThreadInterrupts();
Monitor* monitor = new Monitor();
@@ -134,7 +134,6 @@
// Ensure that our particular zone is visited.
isolate_->IterateObjectPointers(
&counter,
- /* visit_prologue_weak_handles = */ true,
StackFrameIterator::kValidateFrames);
EXPECT_EQ(1, counter.count());
}
@@ -152,7 +151,6 @@
// Ensure that our particular zone is visited.
isolate_->IterateObjectPointers(
&str_counter,
- /* visit_prologue_weak_handles = */ true,
StackFrameIterator::kValidateFrames);
// We should visit the string object exactly once.
EXPECT_EQ(1, str_counter.count());
@@ -279,7 +277,6 @@
ObjectCounter counter(isolate_, &smi);
isolate_->IterateObjectPointers(
&counter,
- /* visit_prologue_weak_handles = */ true,
StackFrameIterator::kValidateFrames);
{
MutexLocker ml(mutex_);
@@ -410,18 +407,18 @@
intptr_t thread_count_1 = 0;
{
- ThreadIterator ti;
+ OSThreadIterator ti;
while (ti.HasNext()) {
- Thread* thread = ti.Next();
+ OSThread* thread = ti.Next();
EXPECT(thread != NULL);
thread_count_0++;
}
}
{
- ThreadIterator ti;
+ OSThreadIterator ti;
while (ti.HasNext()) {
- Thread* thread = ti.Next();
+ OSThread* thread = ti.Next();
EXPECT(thread != NULL);
thread_count_1++;
}
@@ -434,8 +431,8 @@
TEST_CASE(ThreadIterator_FindSelf) {
- Thread* current = Thread::Current();
- EXPECT(Thread::IsThreadInList(current->join_id()));
+ OSThread* current = OSThread::Current();
+ EXPECT(OSThread::IsThreadInList(current->join_id()));
}
@@ -446,16 +443,15 @@
void ThreadIteratorTestMain(uword parameter) {
- Thread::EnsureInit();
ThreadIteratorTestParams* params =
reinterpret_cast<ThreadIteratorTestParams*>(parameter);
- Thread* thread = Thread::Current();
+ OSThread* thread = OSThread::Current();
EXPECT(thread != NULL);
MonitorLocker ml(params->monitor);
params->spawned_thread_join_id = thread->join_id();
EXPECT(params->spawned_thread_join_id != OSThread::kInvalidThreadJoinId);
- EXPECT(Thread::IsThreadInList(thread->join_id()));
+ EXPECT(OSThread::IsThreadInList(thread->join_id()));
ml.Notify();
}
@@ -471,7 +467,9 @@
MonitorLocker ml(params.monitor);
EXPECT(params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId);
// Spawn thread and wait to receive the thread join id.
- OSThread::Start(ThreadIteratorTestMain, reinterpret_cast<uword>(¶ms));
+ OSThread::Start("ThreadIteratorTest",
+ ThreadIteratorTestMain,
+ reinterpret_cast<uword>(¶ms));
while (params.spawned_thread_join_id == OSThread::kInvalidThreadJoinId) {
ml.Wait();
}
@@ -480,7 +478,7 @@
OSThread::Join(params.spawned_thread_join_id);
}
- EXPECT(!Thread::IsThreadInList(params.spawned_thread_join_id))
+ EXPECT(!OSThread::IsThreadInList(params.spawned_thread_join_id))
delete params.monitor;
}
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index d840767..331fb52 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -126,9 +126,9 @@
}
// Iterate over threads.
- ThreadIterator it;
+ OSThreadIterator it;
while (it.HasNext()) {
- Thread* thread = it.Next();
+ OSThread* thread = it.Next();
MutexLocker ml(thread->timeline_block_lock());
// Grab block and clear it.
TimelineEventBlock* block = thread->timeline_block();
@@ -350,7 +350,9 @@
set_event_type(event_type);
timestamp0_ = 0;
timestamp1_ = 0;
- thread_ = OSThread::GetCurrentThreadTraceId();
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ thread_ = os_thread->trace_id();
Isolate* isolate = Isolate::Current();
if (isolate != NULL) {
isolate_id_ = isolate->main_port();
@@ -641,9 +643,9 @@
void TimelineEventRecorder::PrintJSONMeta(JSONArray* events) const {
- ThreadIterator it;
+ OSThreadIterator it;
while (it.HasNext()) {
- Thread* thread = it.Next();
+ OSThread* thread = it.Next();
const char* thread_name = thread->name();
if (thread_name == NULL) {
// Only emit a thread name if one was set.
@@ -666,7 +668,7 @@
TimelineEvent* TimelineEventRecorder::ThreadBlockStartEvent() {
// Grab the current thread.
- Thread* thread = Thread::Current();
+ OSThread* thread = OSThread::Current();
ASSERT(thread != NULL);
Mutex* thread_block_lock = thread->timeline_block_lock();
ASSERT(thread_block_lock != NULL);
@@ -707,7 +709,7 @@
return;
}
// Grab the current thread.
- Thread* thread = Thread::Current();
+ OSThread* thread = OSThread::Current();
ASSERT(thread != NULL);
// Unlock the thread's block lock.
Mutex* thread_block_lock = thread->timeline_block_lock();
@@ -901,9 +903,6 @@
TimelineEvent* TimelineEventRingRecorder::StartEvent() {
- // Grab the current thread.
- Thread* thread = Thread::Current();
- ASSERT(thread != NULL);
return ThreadBlockStartEvent();
}
@@ -986,9 +985,6 @@
TimelineEvent* TimelineEventEndlessRecorder::StartEvent() {
- // Grab the current thread.
- Thread* thread = Thread::Current();
- ASSERT(thread != NULL);
return ThreadBlockStartEvent();
}
@@ -1045,7 +1041,7 @@
}
head_ = NULL;
block_index_ = 0;
- Thread* thread = Thread::Current();
+ OSThread* thread = OSThread::Current();
thread->set_timeline_block(NULL);
}
@@ -1067,8 +1063,10 @@
TimelineEvent* TimelineEventBlock::StartEvent() {
ASSERT(!IsFull());
if (FLAG_trace_timeline) {
- OS::Print("StartEvent in block %p for thread %" Px "\n",
- this, OSThread::CurrentCurrentThreadIdAsIntPtr());
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ intptr_t tid = OSThread::ThreadIdToIntPtr(os_thread->id());
+ OS::Print("StartEvent in block %p for thread %" Px "\n", this, tid);
}
return &events_[length_++];
}
@@ -1119,7 +1117,9 @@
void TimelineEventBlock::Open() {
- thread_id_ = OSThread::GetCurrentThreadTraceId();
+ OSThread* os_thread = OSThread::Current();
+ ASSERT(os_thread != NULL);
+ thread_id_ = os_thread->trace_id();
in_use_ = true;
}
diff --git a/runtime/vm/timeline_test.cc b/runtime/vm/timeline_test.cc
index 00fc839..2d9bb57 100644
--- a/runtime/vm/timeline_test.cc
+++ b/runtime/vm/timeline_test.cc
@@ -478,7 +478,9 @@
ASSERT(recorder != NULL);
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- ThreadId tid = OSThread::GetCurrentThreadTraceId();
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ ThreadId tid = os_thread->trace_id();
// Test case.
TimelineTestHelper::FakeDuration(recorder, "a", 0, 10);
@@ -648,7 +650,9 @@
ASSERT(recorder != NULL);
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- ThreadId tid = OSThread::GetCurrentThreadTraceId();
+ OSThread* os_thread = thread->os_thread();
+ ASSERT(os_thread != NULL);
+ ThreadId tid = os_thread->trace_id();
// Test case.
TimelineTestHelper::FakeBegin(recorder, "a", 0);
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 6e1ca5c..a8b063a 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -360,36 +360,44 @@
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 @@
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,
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index 556a738..18ad438 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -79,12 +79,10 @@
VerifyPointersVisitor visitor(isolate, allocated_set);
// Visit all strongly reachable objects.
isolate->IterateObjectPointers(&visitor,
- false, // skip prologue weak handles
StackFrameIterator::kValidateFrames);
VerifyWeakPointersVisitor weak_visitor(&visitor);
// Visit weak handles and prologue weak handles.
- isolate->VisitWeakPersistentHandles(&weak_visitor,
- true); // visit prologue weak handles
+ isolate->VisitWeakPersistentHandles(&weak_visitor);
delete allocated_set;
}
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 9771a91..b3df320 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -96,6 +96,69 @@
}]],
},
{
+ 'target_name': 'libdart_vm_precompiled',
+ 'type': 'static_library',
+ 'toolsets':['host', 'target'],
+ 'includes': [
+ 'vm_sources.gypi',
+ '../platform/platform_headers.gypi',
+ '../platform/platform_sources.gypi',
+ ],
+ 'sources/': [
+ # Exclude all _test.[cc|h] files.
+ ['exclude', '_test\\.(cc|h)$'],
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'defines': [
+ 'DART_PRECOMPILED',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lpthread',
+ '-lrt',
+ '-ldl',
+ ],
+ },
+ }],
+ ['OS=="android" and _toolset=="host"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lpthread',
+ '-lrt',
+ '-ldl',
+ ],
+ },
+ }],
+ ['OS=="win"', {
+ 'sources/' : [
+ ['exclude', 'gdbjit.cc'],
+ ],
+ }],
+ ['dart_vtune_support==0', {
+ 'sources/' : [
+ ['exclude', 'vtune\\.(cc|h)$'],
+ ],
+ }],
+ ['dart_vtune_support==1', {
+ 'include_dirs': ['<(dart_vtune_root)/include'],
+ 'defines': ['DART_VTUNE_SUPPORT'],
+ 'link_settings': {
+ 'conditions': [
+ ['OS=="linux"', {
+ 'libraries': ['-ljitprofiling'],
+ }],
+ ['OS=="win"', {
+ 'libraries': ['-ljitprofiling.lib'],
+ }],
+ ],
+ },
+ }]],
+ },
+ {
'target_name': 'libdart_vm_nosnapshot',
'type': 'static_library',
'toolsets':['host', 'target'],
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 228abcb..f2cf962 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -315,6 +315,7 @@
'os_linux.cc',
'os_macos.cc',
'os_test.cc',
+ 'os_thread.cc',
'os_thread.h',
'os_thread_android.cc',
'os_thread_android.h',
diff --git a/sdk/bin/dart2js b/sdk/bin/dart2js
index f448ba8..485d619 100755
--- a/sdk/bin/dart2js
+++ b/sdk/bin/dart2js
@@ -54,7 +54,7 @@
if [ -z "$DART_CONFIGURATION" ];
then
- DART_CONFIGURATION="ReleaseIA32"
+ DART_CONFIGURATION="ReleaseX64"
fi
if [[ `uname` == 'Darwin' ]]; then
diff --git a/sdk/bin/dartanalyzer b/sdk/bin/dartanalyzer
index 9b4a2ab..c793551 100755
--- a/sdk/bin/dartanalyzer
+++ b/sdk/bin/dartanalyzer
@@ -43,7 +43,7 @@
DART_ROOT="$(cd "${SDK_DIR}/.." ; pwd -P)"
-ANALYZER="$DART_ROOT/third_party/pkg/analyzer_cli/bin/analyzer.dart"
+ANALYZER="$DART_ROOT/pkg/analyzer_cli/bin/analyzer.dart"
if [[ `uname` == 'Darwin' ]];
then
diff --git a/sdk/bin/dartanalyzer.bat b/sdk/bin/dartanalyzer.bat
index ef041b0..0e0cb10 100644
--- a/sdk/bin/dartanalyzer.bat
+++ b/sdk/bin/dartanalyzer.bat
@@ -38,7 +38,7 @@
rem Remove trailing backslash if there is one
if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
-set ANALYZER=%DART_ROOT%\third_party\pkg\analyzer_cli\bin\analyzer.dart
+set ANALYZER=%DART_ROOT%\pkg\analyzer_cli\bin\analyzer.dart
rem DART_CONFIGURATION defaults to ReleaseIA32
if "%DART_CONFIGURATION%"=="" set DART_CONFIGURATION=ReleaseIA32
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index 301517e..9dd31a4 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -5,21 +5,22 @@
// Patch file for dart:core classes.
import "dart:_internal" as _symbol_dev;
import 'dart:_interceptors';
-import 'dart:_js_helper' show patch,
+import 'dart:_js_helper' show checkInt,
+ Closure,
+ ConstantMap,
+ getRuntimeType,
+ JsLinkedHashMap,
+ jsonEncodeNative,
+ JSSyntaxRegExp,
+ NoInline,
+ objectHashCode,
+ patch,
patch_full,
patch_lazy,
patch_startup,
- checkInt,
- getRuntimeType,
- jsonEncodeNative,
- JSSyntaxRegExp,
Primitives,
- ConstantMap,
- stringJoinUnchecked,
- objectHashCode,
- Closure,
readHttp,
- JsLinkedHashMap;
+ stringJoinUnchecked;
import 'dart:_foreign_helper' show JS;
@@ -671,3 +672,24 @@
});
}
}
+
+@patch
+class StackTrace {
+ @patch
+ @NoInline()
+ static StackTrace get current {
+ var error = JS('', 'new Error()');
+ var stack = JS('String|Null', '#.stack', error);
+ if (stack is String) return new StackTrace.fromString(stack);
+ if (JS('', 'Error.captureStackTrace') != null) {
+ JS('void', 'Error.captureStackTrace(#)', error);
+ var stack = JS('String|Null', '#.stack', error);
+ if (stack is String) return new StackTrace.fromString(stack);
+ }
+ try {
+ throw 0;
+ } catch (_, stackTrace) {
+ return stackTrace;
+ }
+ }
+}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 30016f7..bcc2019 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -254,9 +254,9 @@
* The call to `cleanUp` should not throw. If it does, the error will be an
* uncaught asynchronous error.
*/
- static Future<List> wait(Iterable<Future> futures,
+ static Future<List/*<T>*/> wait/*<T>*/(Iterable<Future/*<T>*/> futures,
{bool eagerError: false,
- void cleanUp(successValue)}) {
+ void cleanUp(/*=T*/ successValue)}) {
final _Future<List> result = new _Future<List>();
List values; // Collects the values. Set to null on error.
int remaining = 0; // How many futures are we waiting for.
@@ -407,7 +407,7 @@
* with a `test` parameter, instead of handling both value and error in a
* single [then] call.
*/
- Future then(onValue(T value), { Function onError });
+ Future/*<S>*/ then/*<S>*/(/*=S*/ onValue(T value), { Function onError });
/**
* Handles errors emitted by this [Future].
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index acc4036..fac3f7f 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.dart
@@ -8,9 +8,8 @@
class _AsyncCallbackEntry {
final _AsyncCallback callback;
- final Zone zone;
_AsyncCallbackEntry next;
- _AsyncCallbackEntry(this.callback, this.zone);
+ _AsyncCallbackEntry(this.callback);
}
/** Head of single linked list of pending callbacks. */
@@ -39,23 +38,21 @@
_AsyncCallbackEntry entry = _nextCallback;
_nextCallback = entry.next;
if (_nextCallback == null) _lastCallback = null;
- Zone._current = entry.zone;
- entry.callback();
+ (entry.callback)();
}
}
-void _microtaskLoopEntry() {
+void _startMicrotaskLoop() {
_isInCallbackLoop = true;
try {
// Moved to separate function because try-finally prevents
// good optimization.
_microtaskLoop();
} finally {
- Zone._current = _ROOT_ZONE;
_lastPriorityCallback = null;
_isInCallbackLoop = false;
if (_nextCallback != null) {
- _AsyncRun._scheduleImmediate(_microtaskLoopEntry);
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
}
}
@@ -66,11 +63,12 @@
* The microtask is called after all other currently scheduled
* microtasks, but as part of the current system event.
*/
-void _scheduleAsyncCallback(_AsyncCallbackEntry newEntry) {
+void _scheduleAsyncCallback(_AsyncCallback callback) {
+ _AsyncCallbackEntry newEntry = new _AsyncCallbackEntry(callback);
if (_nextCallback == null) {
_nextCallback = _lastCallback = newEntry;
if (!_isInCallbackLoop) {
- _AsyncRun._scheduleImmediate(_microtaskLoopEntry);
+ _AsyncRun._scheduleImmediate(_startMicrotaskLoop);
}
} else {
_lastCallback.next = newEntry;
@@ -87,12 +85,13 @@
* Is always run in the root zone.
*/
void _schedulePriorityAsyncCallback(callback) {
- _AsyncCallbackEntry entry =
- new _AsyncCallbackEntry(callback, _ROOT_ZONE);
if (_nextCallback == null) {
- _scheduleAsyncCallback(entry);
+ _scheduleAsyncCallback(callback);
_lastPriorityCallback = _lastCallback;
- } else if (_lastPriorityCallback == null) {
+ return;
+ }
+ _AsyncCallbackEntry entry = new _AsyncCallbackEntry(callback);
+ if (_lastPriorityCallback == null) {
entry.next = _nextCallback;
_nextCallback = _lastPriorityCallback = entry;
} else {
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 7766c81a..ae003e3 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -317,8 +317,8 @@
* If a broadcast stream is listened to more than once, each subscription
* will individually execute `map` for each event.
*/
- Stream map(convert(T event)) {
- return new _MapStream<T, dynamic>(this, convert);
+ Stream/*<S>*/ map/*<S>*/(/*=S*/ convert(T event)) {
+ return new _MapStream<T, dynamic/*=S*/>(this, convert);
}
/**
@@ -479,8 +479,8 @@
* If a broadcast stream is listened to more than once, each subscription
* will individually call `convert` and expand the events.
*/
- Stream expand(Iterable convert(T value)) {
- return new _ExpandStream<T, dynamic>(this, convert);
+ Stream/*<S>*/ expand(Iterable/*<S>*/ convert(T value)) {
+ return new _ExpandStream<T, dynamic/*=S*/>(this, convert);
}
/**
@@ -554,7 +554,9 @@
}
/** Reduces a sequence of values by repeatedly applying [combine]. */
- Future fold(var initialValue, combine(var previous, T element)) {
+ Future/*<S>*/ fold/*<S>*/(var/*=S*/ initialValue,
+ /*=S*/ combine(var/*=S*/ previous, T element)) {
+
_Future result = new _Future();
var value = initialValue;
StreamSubscription subscription;
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 2520f4d..d84f01b 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -958,7 +958,7 @@
// Use root zone as event zone if the function is already bound.
zone = _ROOT_ZONE;
}
- _scheduleAsyncCallback(new _AsyncCallbackEntry(f, zone));
+ _scheduleAsyncCallback(f);
}
Timer _rootCreateTimer(Zone self, ZoneDelegate parent, Zone zone,
diff --git a/sdk/lib/collection/iterable.dart b/sdk/lib/collection/iterable.dart
index e89acc6f..c0d2ee0 100644
--- a/sdk/lib/collection/iterable.dart
+++ b/sdk/lib/collection/iterable.dart
@@ -15,12 +15,13 @@
// - SetMixin
// If changing a method here, also change the other copies.
- Iterable map(f(E element)) => new MappedIterable<E, dynamic>(this, f);
+ Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E element)) =>
+ new MappedIterable<E, dynamic/*=T*/>(this, f);
Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
- Iterable expand(Iterable f(E element)) =>
- new ExpandIterable<E, dynamic>(this, f);
+ Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) =>
+ new ExpandIterable<E, dynamic/*=T*/>(this, f);
bool contains(Object element) {
for (E e in this) {
@@ -45,8 +46,8 @@
return value;
}
- dynamic fold(var initialValue,
- dynamic combine(var previousValue, E element)) {
+ dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+ dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) {
var value = initialValue;
for (E element in this) value = combine(value, element);
return value;
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 0229732..a47838b 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -165,12 +165,11 @@
/**
* Create an argument error for a `null` argument that must not be `null`.
- *
- * Shorthand for calling [ArgumentError.value] with a `null` value and a
- * message of `"Must not be null"`.
*/
- ArgumentError.notNull([String name])
- : this.value(null, name, "Must not be null");
+ ArgumentError.notNull([this.name])
+ : _hasValue = false,
+ message = "Must not be null",
+ invalidValue = null;
// Helper functions for toString overridden in subclasses.
String get _errorName => "Invalid argument${!_hasValue ? "(s)" : ""}";
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index a327b6d..dd19502 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -156,7 +156,8 @@
* on any element where the result isn't needed.
* For example, [elementAt] may call `f` only once.
*/
- Iterable map(f(E element)) => new MappedIterable<E, dynamic>(this, f);
+ Iterable/*<T>*/ map/*<T>*/(/*=T*/ f(E e)) =>
+ new MappedIterable<E, dynamic/*=T*/>(this, f);
/**
* Returns a new lazy [Iterable] with all elements that satisfy the
@@ -182,8 +183,8 @@
* The returned [Iterable] is lazy, and calls [f] for each element
* of this every time it's iterated.
*/
- Iterable expand(Iterable f(E element)) =>
- new ExpandIterable<E, dynamic>(this, f);
+ Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) =>
+ new ExpandIterable<E, dynamic/*=T*/>(this, f);
/**
* Returns true if the collection contains an element equal to [element].
@@ -270,8 +271,8 @@
* iterable.fold(0, (prev, element) => prev + element);
*
*/
- dynamic fold(var initialValue,
- dynamic combine(var previousValue, E element)) {
+ dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue,
+ dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) {
var value = initialValue;
for (E element in this) value = combine(value, element);
return value;
diff --git a/sdk/lib/core/pattern.dart b/sdk/lib/core/pattern.dart
index f47ba15..7f32c72 100644
--- a/sdk/lib/core/pattern.dart
+++ b/sdk/lib/core/pattern.dart
@@ -42,3 +42,90 @@
*/
Match matchAsPrefix(String string, [int start = 0]);
}
+
+/**
+ * A result from searching within a string.
+ *
+ * A Match or an [Iterable] of Match objects is returned from [Pattern]
+ * matching methods.
+ *
+ * The following example finds all matches of a [RegExp] in a [String]
+ * and iterates through the returned iterable of Match objects.
+ *
+ * RegExp exp = new RegExp(r"(\w+)");
+ * String str = "Parse my string";
+ * Iterable<Match> matches = exp.allMatches(str);
+ * for (Match m in matches) {
+ * String match = m.group(0);
+ * print(match);
+ * }
+ *
+ * The output of the example is:
+ *
+ * Parse
+ * my
+ * string
+ *
+ * Some patterns, regular expressions in particular, may record subtrings
+ * that were part of the matching. These are called _groups_ in the Match
+ * object. Some patterns may never have any groups, and their matches always
+ * have zero [groupCount].
+ */
+abstract class Match {
+ /**
+ * Returns the index in the string where the match starts.
+ */
+ int get start;
+
+ /**
+ * Returns the index in the string after the last character of the
+ * match.
+ */
+ int get end;
+
+ /**
+ * Returns the string matched by the given [group].
+ *
+ * If [group] is 0, returns the match of the pattern.
+ *
+ * The result may be `null` if the pattern didn't assign a value to it
+ * as part of this match.
+ */
+ String group(int group);
+
+ /**
+ * Returns the string matched by the given [group].
+ *
+ * If [group] is 0, returns the match of the pattern.
+ *
+ * Short alias for [Match.group].
+ */
+ String operator [](int group);
+
+ /**
+ * Returns a list of the groups with the given indices.
+ *
+ * The list contains the strings returned by [group] for each index in
+ * [groupIndices].
+ */
+ List<String> groups(List<int> groupIndices);
+
+ /**
+ * Returns the number of captured groups in the match.
+ *
+ * Some patterns may capture parts of the input that was used to
+ * compute the full match. This is the number of captured groups,
+ * which is also the maximal allowed argument to the [group] method.
+ */
+ int get groupCount;
+
+ /**
+ * The string on which this match was computed.
+ */
+ String get input;
+
+ /**
+ * The pattern used to search in [input].
+ */
+ Pattern get pattern;
+}
\ No newline at end of file
diff --git a/sdk/lib/core/regexp.dart b/sdk/lib/core/regexp.dart
index 049ff97..0d92345 100644
--- a/sdk/lib/core/regexp.dart
+++ b/sdk/lib/core/regexp.dart
@@ -5,94 +5,6 @@
part of dart.core;
/**
- * A result from searching within a string.
- *
- * A Match or an [Iterable] of Match objects is returned from [Pattern]
- * matching methods.
- *
- * The following example finds all matches of a [RegExp] in a [String]
- * and iterates through the returned iterable of Match objects.
- *
- * RegExp exp = new RegExp(r"(\w+)");
- * String str = "Parse my string";
- * Iterable<Match> matches = exp.allMatches(str);
- * for (Match m in matches) {
- * String match = m.group(0);
- * print(match);
- * }
- *
- * The output of the example is:
- *
- * Parse
- * my
- * string
- *
- * Some patterns, regular expressions in particular, may record subtrings
- * that were part of the matching. These are called _groups_ in the Match
- * object. Some patterns may never have any groups, and their matches always
- * have zero [groupCount].
- */
-abstract class Match {
- /**
- * Returns the index in the string where the match starts.
- */
- int get start;
-
- /**
- * Returns the index in the string after the last character of the
- * match.
- */
- int get end;
-
- /**
- * Returns the string matched by the given [group].
- *
- * If [group] is 0, returns the match of the pattern.
- *
- * The result may be `null` if the pattern didn't assign a value to it
- * as part of this match.
- */
- String group(int group);
-
- /**
- * Returns the string matched by the given [group].
- *
- * If [group] is 0, returns the match of the pattern.
- *
- * Short alias for [Match.group].
- */
- String operator [](int group);
-
- /**
- * Returns a list of the groups with the given indices.
- *
- * The list contains the strings returned by [group] for each index in
- * [groupIndices].
- */
- List<String> groups(List<int> groupIndices);
-
- /**
- * Returns the number of captured groups in the match.
- *
- * Some patterns may capture parts of the input that was used to
- * compute the full match. This is the number of captured groups,
- * which is also the maximal allowed argument to the [group] method.
- */
- int get groupCount;
-
- /**
- * The string on which this match was computed.
- */
- String get input;
-
- /**
- * The pattern used to search in [input].
- */
- Pattern get pattern;
-}
-
-
-/**
* A regular expression pattern.
*
* Regular expressions are [Pattern]s, and can as such be used to match strings
diff --git a/sdk/lib/core/stacktrace.dart b/sdk/lib/core/stacktrace.dart
index c8540dc..17abd38 100644
--- a/sdk/lib/core/stacktrace.dart
+++ b/sdk/lib/core/stacktrace.dart
@@ -31,6 +31,18 @@
factory StackTrace.fromString(String stackTraceString) = _StringStackTrace;
/**
+ * Returns a representation of the current stack trace.
+ *
+ * This is similar to what can be achieved by doing:
+ *
+ * try { throw 0; } catch (_, stack) { return stack; }
+ *
+ * The getter achieves this without throwing, except on platforms that
+ * have no other way to get a stack trace.
+ */
+ external static StackTrace get current;
+
+ /**
* Returns a [String] representation of the stack trace.
*
* The string represents the full stack trace starting from
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index d3b2073..8acae64 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -8464,7 +8464,26 @@
@DomName('DedicatedWorkerGlobalScope.postMessage')
@DocsEditable()
@Experimental() // untriaged
- void postMessage(Object message, [List<MessagePort> transfer]) native;
+ void postMessage(/*any*/ message, [List<MessagePort> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+ @JSName('postMessage')
+ @DomName('DedicatedWorkerGlobalScope.postMessage')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void _postMessage_1(message, List<MessagePort> transfer) native;
+ @JSName('postMessage')
+ @DomName('DedicatedWorkerGlobalScope.postMessage')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void _postMessage_2(message) native;
/// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
@DomName('DedicatedWorkerGlobalScope.onmessage')
@@ -9846,32 +9865,29 @@
@DomName('Document.createElement')
Element createElement(String tagName, [String typeExtension]) {
- if (typeExtension == null) {
- return _createElement_2(tagName);
- } else {
- return _createElement(tagName, typeExtension);
- }
+ return (typeExtension == null)
+ ? _createElement_2(tagName)
+ : _createElement(tagName, typeExtension);
}
// The two-argument version of this is automatically generated, but we need to
// omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
@DomName('Document.createElement')
- _createElement_2(String tagName) => JS('', '#.createElement(#)', this, tagName);
+ _createElement_2(String tagName) =>
+ JS('Element', '#.createElement(#)', this, tagName);
// The three-argument version of this is automatically generated, but we need to
// omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
@DomName('Document.createElementNS')
_createElementNS_2(String namespaceURI, String qualifiedName) =>
- JS('', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+ JS('Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
@DomName('Document.createElementNS')
@DocsEditable()
Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
- if (typeExtension == null) {
- return _createElementNS_2(namespaceURI, qualifiedName);
- } else {
- return _createElementNS(namespaceURI, qualifiedName, typeExtension);
- }
+ return (typeExtension == null)
+ ? _createElementNS_2(namespaceURI, qualifiedName)
+ : _createElementNS(namespaceURI, qualifiedName, typeExtension);
}
@DomName('Document.createNodeIterator')
@@ -27430,7 +27446,26 @@
@DomName('ServiceWorkerClient.postMessage')
@DocsEditable()
@Experimental() // untriaged
- void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) native;
+ void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+ @JSName('postMessage')
+ @DomName('ServiceWorkerClient.postMessage')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void _postMessage_1(message, List<MessagePort> transfer) native;
+ @JSName('postMessage')
+ @DomName('ServiceWorkerClient.postMessage')
+ @DocsEditable()
+ @Experimental() // untriaged
+ void _postMessage_2(message) native;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -31921,9 +31956,9 @@
*
* ## Other resources
*
- * * [Loading web pages]
- * (http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html)
- * from WHATWG.
+ * * [Loading web
+ * pages](https://html.spec.whatwg.org/multipage/browsers.html)
+ * from WHATWG.
*/
Document get document => JS('Document', '#.document', this);
@@ -31937,10 +31972,10 @@
*
* ## Other resources
*
- * * [Window.open]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.open) from MDN.
- * * [Window open]
- * (http://docs.webplatform.org/wiki/dom/methods/open) from WebPlatform.org.
+ * * [Window.open](https://developer.mozilla.org/en-US/docs/Web/API/Window.open)
+ * from MDN.
+ * * [Window open](http://docs.webplatform.org/wiki/dom/methods/open)
+ * from WebPlatform.org.
*/
WindowBase open(String url, String name, [String options]) {
if (options == null) {
@@ -32002,8 +32037,8 @@
*
* ## Other resources
*
- * * [Window.cancelAnimationFrame]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame) from MDN.
+ * * [Window.cancelAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/Window.cancelAnimationFrame)
+ * from MDN.
*/
void cancelAnimationFrame(int id) {
_ensureRequestAnimationFrame();
@@ -33772,10 +33807,10 @@
*
* ## Other resources
*
- * * [Window.moveTo]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo) from MDN.
- * * [Window.moveTo]
- * (http://dev.w3.org/csswg/cssom-view/#dom-window-moveto) from W3C.
+ * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+ * from MDN.
+ * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+ * from W3C.
*/
void moveTo(Point p) {
_moveTo(p.x, p.y);
@@ -33794,10 +33829,10 @@
*
* ## Other resources
*
- * * [The Screen interface specification]
- * (http://www.w3.org/TR/cssom-view/#screen) from W3C.
- * * [scrollX]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX) from MDN.
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollX](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollX)
+ * from MDN.
*/
@DomName('Window.scrollX')
@DocsEditable()
@@ -33810,10 +33845,10 @@
*
* ## Other resources
*
- * * [The Screen interface specification]
- * (http://www.w3.org/TR/cssom-view/#screen) from W3C.
- * * [scrollY]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY) from MDN.
+ * * [The Screen interface
+ * specification](http://www.w3.org/TR/cssom-view/#screen) from W3C.
+ * * [scrollY](https://developer.mozilla.org/en-US/docs/Web/API/Window.scrollY)
+ * from MDN.
*/
@DomName('Window.scrollY')
@DocsEditable()
@@ -34020,7 +34055,24 @@
@DomName('Worker.postMessage')
@DocsEditable()
- void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) native;
+ void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) {
+ if (transfer != null) {
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_1(message_1, transfer);
+ return;
+ }
+ var message_1 = convertDartToNative_SerializedScriptValue(message);
+ _postMessage_2(message_1);
+ return;
+ }
+ @JSName('postMessage')
+ @DomName('Worker.postMessage')
+ @DocsEditable()
+ void _postMessage_1(message, List<MessagePort> transfer) native;
+ @JSName('postMessage')
+ @DomName('Worker.postMessage')
+ @DocsEditable()
+ void _postMessage_2(message) native;
@DomName('Worker.terminate')
@DocsEditable()
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index cc87949..6b1a7f7 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -9535,7 +9535,7 @@
@DomName('DedicatedWorkerGlobalScope.postMessage')
@DocsEditable()
@Experimental() // untriaged
- void postMessage(Object message, [List<MessagePort> transfer]) => _blink.BlinkDedicatedWorkerGlobalScope.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+ void postMessage(Object message, [List<MessagePort> transfer]) => _blink.BlinkDedicatedWorkerGlobalScope.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
/// Stream of `message` events handled by this [DedicatedWorkerGlobalScope].
@DomName('DedicatedWorkerGlobalScope.onmessage')
@@ -33019,7 +33019,7 @@
@DomName('ServiceWorkerClient.postMessage')
@DocsEditable()
@Experimental() // untriaged
- void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkServiceWorkerClient.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+ void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkServiceWorkerClient.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -40454,10 +40454,10 @@
*
* ## Other resources
*
- * * [Window.moveTo]
- * (https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo) from MDN.
- * * [Window.moveTo]
- * (http://dev.w3.org/csswg/cssom-view/#dom-window-moveto) from W3C.
+ * * [Window.moveTo](https://developer.mozilla.org/en-US/docs/Web/API/Window.moveTo)
+ * from MDN.
+ * * [Window.moveTo](http://dev.w3.org/csswg/cssom-view/#dom-window-moveto)
+ * from W3C.
*/
void moveTo(Point p) {
_moveTo(p.x, p.y);
@@ -40677,7 +40677,7 @@
@DomName('Worker.postMessage')
@DocsEditable()
- void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkWorker.instance.postMessage_Callback_2_(unwrap_jso(this), message, transfer);
+ void postMessage(/*SerializedScriptValue*/ message, [List<MessagePort> transfer]) => _blink.BlinkWorker.instance.postMessage_Callback_2_(unwrap_jso(this), convertDartToNative_SerializedScriptValue(message), transfer);
@DomName('Worker.terminate')
@DocsEditable()
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index 3b3a8ad..b7f3d7c 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -88,7 +88,7 @@
var completer = new Completer();
var then = convertDartClosureToJS((result) => completer.complete(result), 1);
var error = convertDartClosureToJS((result) => completer.completeError(result), 1);
- var newPromise = JS('', '#.then(#).catch(#)', promise, then, error);
+ var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
return completer.future;
}
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 034b2ce..1f80c9d 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -380,7 +380,7 @@
List storeNames_1 = convertDartToNative_StringArray(storeNames);
return _transaction(storeNames_1, mode);
}
-
+
Transaction transactionStores(DomStringList storeNames, String mode) {
if (mode != 'readonly' && mode != 'readwrite') {
throw new ArgumentError(mode);
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index c75130a..4ab3e30 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -292,6 +292,27 @@
return _createObjectStore(name, options);
}
+ Transaction transaction(storeName_OR_storeNames, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError("Invalid transaction mode $mode");
+ }
+ var names;
+ if (storeName_OR_storeNames == null) {
+ throw new ArgumentError("stores may not be null in transaction");
+ } else if (storeName_OR_storeNames is String || storeName_OR_storeNames is DomStringList) {
+ names = unwrap_jso(storeName_OR_storeNames);
+ } else if (storeName_OR_storeNames is List<String>) {
+ names = convertDartToNative_List(storeName_OR_storeNames);
+ } else {
+ throw new ArgumentError("Invalid store(s) $store_Name_OR_storeNames");
+ }
+
+ return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), names, mode));
+ }
+
+ Transaction transactionList(List<String> storeNames, String mode) => transaction(storeNames, mode);
+ Transaction transactionStores(List<String> storeNames, String mode) => transaction(storeNames, mode);
+ Transaction transactionStore(String storeName, String mode) => transaction(storeName, mode);
// To suppress missing implicit constructor warnings.
factory Database._() { throw new UnsupportedError("Not supported"); }
@@ -379,49 +400,6 @@
@DocsEditable()
void deleteObjectStore(String name) => _blink.BlinkIDBDatabase.instance.deleteObjectStore_Callback_1_(unwrap_jso(this), name);
- Transaction transaction(storeName_OR_storeNames, [String mode]) {
- if ((storeName_OR_storeNames is String || storeName_OR_storeNames == null) && mode == null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
- }
- if ((mode is String || mode == null) && (storeName_OR_storeNames is String || storeName_OR_storeNames == null)) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
- }
- if ((storeName_OR_storeNames is List<String> || storeName_OR_storeNames == null) && mode == null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
- }
- if ((mode is String || mode == null) && (storeName_OR_storeNames is List<String> || storeName_OR_storeNames == null)) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
- }
- if ((storeName_OR_storeNames is DomStringList || storeName_OR_storeNames == null) && mode == null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames)));
- }
- if ((mode is String || mode == null) && (storeName_OR_storeNames is DomStringList || storeName_OR_storeNames == null)) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeName_OR_storeNames), mode));
- }
- throw new ArgumentError("Incorrect number or type of arguments");
- }
-
- Transaction transactionList(List<String> storeNames, [String mode]) {
- if (mode != null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), convertDartToNative_StringArray(storeNames), mode));
- }
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), convertDartToNative_StringArray(storeNames)));
- }
-
- Transaction transactionStore(String storeName, [String mode]) {
- if (mode != null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), storeName, mode));
- }
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), storeName));
- }
-
- Transaction transactionStores(List<String> storeNames, [String mode]) {
- if (mode != null) {
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), unwrap_jso(storeNames), mode));
- }
- return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_1_(unwrap_jso(this), unwrap_jso(storeNames)));
- }
-
/// Stream of `abort` events handled by this [Database].
@DomName('IDBDatabase.onabort')
@DocsEditable()
diff --git a/sdk/lib/math/math.dart b/sdk/lib/math/math.dart
index d167d80..9182442 100644
--- a/sdk/lib/math/math.dart
+++ b/sdk/lib/math/math.dart
@@ -63,7 +63,7 @@
* same mathematical value) then it is unspecified which of the two arguments
* is returned.
*/
-num min(num a, num b) {
+num/*=T*/ min/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) {
// These partially redundant type checks improve code quality for dart2js.
// Most of the improvement is at call sites from the inferred non-null num
// return type.
@@ -98,7 +98,7 @@
* otherwise equal (including int and doubles with the same mathematical value)
* then it is unspecified which of the two arguments is returned.
*/
-num max(num a, num b) {
+num/*=T*/ max/*<T extends num>*/(num/*=T*/ a, num/*=T*/ b) {
// These partially redundant type checks improve code quality for dart2js.
// Most of the improvement is at call sites from the inferred non-null num
// return type.
diff --git a/sdk/lib/vmservice/asset.dart b/sdk/lib/vmservice/asset.dart
index 7835e74..8155e8a 100644
--- a/sdk/lib/vmservice/asset.dart
+++ b/sdk/lib/vmservice/asset.dart
@@ -38,8 +38,8 @@
}
/// Call to request assets from the embedder.
- static Map<String, Asset> request() {
- Map<String, Asset> assets = new Map<String, Asset>();
+ static HashMap<String, Asset> request() {
+ HashMap<String, Asset> assets = new HashMap<String, Asset>();
Uint8List tarBytes = _requestAssets();
if (tarBytes == null) {
return assets;
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 6c9e8e5..fa7790f 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -5,6 +5,7 @@
library dart._vmservice;
import 'dart:async';
+import 'dart:collection';
import 'dart:convert';
import 'dart:isolate';
import 'dart:typed_data';
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 7b463d9..56ccac3 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -628,6 +628,8 @@
LayoutTests/fast/animation/request-animation-frame-timestamps_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/animation/request-animation-frame-within-callback_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/backgrounds/repeat/parsing-background-repeat_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/backgrounds/background-shorthand-with-backgroundSize-style_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/backgrounds/multiple-backgrounds-computed-style_t01: RuntimeError # co19 issue 14
LayoutTests/fast/borders/border-radius-child_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/2d.fillText.gradient_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/2d.text.draw.fill.maxWidth.gradient_t01: RuntimeError # Please triage this failure
@@ -747,6 +749,8 @@
LayoutTests/fast/css/aspect-ratio-parsing-tests_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/auto-min-size_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/background-position-serialize_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/background-serialize_t01: RuntimeError # https://github.com/dart-lang/co19/issues/14
+LayoutTests/fast/css/css-escaped-identifier_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/checked-pseudo-selector_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/collapsed-whitespace-reattach-in-style-recalc_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/content-language-case-insensitivity_t01: RuntimeError # Issue 23506
@@ -763,6 +767,8 @@
LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/csstext-of-content-string_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/cursor-parsing_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/css/cursor-parsing-image-set_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/cursor-parsing-quirks_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/ex-unit-with-no-x-height_t01: Pass, RuntimeError # Please triage this failure
@@ -776,6 +782,8 @@
LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/fontfaceset-events_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/fontfaceset-loadingdone_t01: Pass, RuntimeError # Please triage this failure
+LayoutTests/fast/css/getComputedStyle/computed-style-border-image_t01: RuntimeError # co19 issue 14
+LayoutTests/fast/css/getComputedStyle/computed-style-cross-fade_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/getComputedStyle/computed-style-font_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/getComputedStyle/computed-style-properties_t01: RuntimeError # Issue 23506
LayoutTests/fast/css/getComputedStyle/counterIncrement-without-counter_t01: RuntimeError # Please triage this failure
@@ -825,8 +833,7 @@
LayoutTests/fast/css/transform-origin-parsing_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/webkit-keyframes-errors_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/word-break-user-modify-allowed-values_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last-inherited_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/css3-text/css3-text-align-last/getComputedStyle/getComputedStyle-text-align-last_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/url-with-multi-byte-unicode-escape_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-line_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css3-text/css3-text-decoration/getComputedStyle/getComputedStyle-text-decoration-style_t01: RuntimeError # Please triage this failure
@@ -1030,6 +1037,7 @@
LayoutTests/fast/forms/select-list-box-mouse-focus_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/forms/select-max-length_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/setrangetext_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/forms/submit-form-attributes_t01: RuntimeError # co19 issue 14
LayoutTests/fast/forms/textarea-paste-newline_t01: RuntimeError # Please triage this failure
LayoutTests/fast/forms/textfield-focus-out_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/forms/validationMessage_t01: RuntimeError # Please triage this failure
@@ -1044,6 +1052,7 @@
LayoutTests/fast/inline/parent-inline-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
LayoutTests/fast/inline/positioned-element-padding-contributes-width_t01: RuntimeError # Please triage this failure
LayoutTests/fast/innerHTML/javascript-url_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
LayoutTests/fast/layers/normal-flow-hit-test_t01: RuntimeError # Please triage this failure
LayoutTests/fast/layers/zindex-hit-test_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/loader/about-blank-hash-change_t01: Skip # Times out. Please triage this failure
@@ -1053,6 +1062,7 @@
LayoutTests/fast/loader/scroll-position-restored-on-back_t01: RuntimeError # Please triage this failure
LayoutTests/fast/loader/scroll-position-restored-on-reload-at-load-event_t01: RuntimeError # Please triage this failure
LayoutTests/fast/loader/stateobjects/replacestate-in-onunload_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/innerHTML/innerHTML-uri-resolution_t01: RuntimeError # co19 issue 14
LayoutTests/fast/masking/parsing-clip-path-shape_t01: RuntimeError # Please triage this failure
LayoutTests/fast/masking/parsing-mask-source-type_t01: RuntimeError # Please triage this failure
LayoutTests/fast/masking/parsing-mask_t01: RuntimeError # Please triage this failure
@@ -1616,10 +1626,6 @@
LayoutTests/fast/text/text-combine-shrink-to-fit_t01: RuntimeError # Please triage this failure
[ $compiler == dart2js && $runtime == chrome && $system == windows ]
-LayoutTests/fast/canvas/canvas-blend-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blend-solid_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-clipping_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-color-over-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-color-over-gradient_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-color-over-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-color-over-pattern_t01: RuntimeError # Please triage this failure
@@ -1628,22 +1634,15 @@
LayoutTests/fast/canvas/canvas-blending-gradient-over-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-gradient-over-gradient_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-gradient-over-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-gradient-over-pattern_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-color_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-gradient_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-image-over-image_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-blending-image-over-pattern_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-pattern-over-color_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-pattern-over-gradient_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-pattern-over-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-pattern-over-pattern_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-shadow_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-blending-transforms_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-alpha_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-canvas_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-composite-image_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-composite-stroke-alpha_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: RuntimeError # Please triage this failure
[ $compiler == dart2js && $runtime == chrome && $system != linux ]
LayoutTests/fast/xpath/py-dom-xpath/abbreviations_t01: RuntimeError # Issue 24398
@@ -1684,7 +1683,6 @@
LayoutTests/fast/canvas/canvas-blending-text_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-composite-canvas_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-composite-image_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/canvas-composite-text-alpha_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-css-crazy_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-currentColor_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/canvas-currentTransform_t01: RuntimeError # Feature is not implemented.
@@ -2480,7 +2478,6 @@
LayoutTests/fast/forms/autofocus-readonly-attribute_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/forms/button/button-disabled-blur_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/forms/button-baseline-and-collapsing_t01: Pass, RuntimeError # Please triage this failure
-LayoutTests/fast/forms/change-form-element-document-crash_t01: RuntimeError # Dartium JSInterop failure, or else Firefox roll error. Issue 24409
LayoutTests/fast/forms/checkValidity-001_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/forms/checkValidity-002_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/forms/checkValidity-004_t01: Pass, RuntimeError # Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index 97e699d..4062b0e 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -827,24 +827,24 @@
LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
LibTest/isolate/RawReceivePort/RawReceivePort_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/RawReceivePort/RawReceivePort_A01_t02: RuntimeError # Issue 13921
-LibTest/isolate/RawReceivePort/close_A01_t01: RuntimeError # Issue 13921
+LibTest/isolate/RawReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
LibTest/isolate/RawReceivePort/handler_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/RawReceivePort/sendPort_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/any_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/any_A01_t02: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/asBroadcastStream_A01_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/asBroadcastStream_A01_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
LibTest/isolate/ReceivePort/asBroadcastStream_A01_t03: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/asBroadcastStream_A01_t04: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/asBroadcastStream_A02_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t02: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/asBroadcastStream_A03_t03: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
LibTest/isolate/ReceivePort/asBroadcastStream_A04_t01: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/asBroadcastStream_A04_t02: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/asBroadcastStream_A04_t03: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/close_A01_t01: RuntimeError # Issue 13921
-LibTest/isolate/ReceivePort/close_A02_t01: RuntimeError # Issue 13921
+LibTest/isolate/ReceivePort/close_A01_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
+LibTest/isolate/ReceivePort/close_A02_t01: Pass, RuntimeError # Issue 13921, co19 issue for false pass https://github.com/dart-lang/co19/issues/13
LibTest/isolate/ReceivePort/contains_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/distinct_A01_t01: RuntimeError # Issue 13921
LibTest/isolate/ReceivePort/distinct_A01_t02: RuntimeError # Issue 13921
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index e0a69f1..bef0984 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -43,7 +43,8 @@
import 'output_collector.dart';
export 'output_collector.dart';
-/// Compile [code] and returns the code for [entry].
+/// Compile [code] and returns either the code for [entry] or, if [returnAll] is
+/// true, the code for the entire program.
///
/// If [check] is provided, it is executed on the code for [entry] before
/// returning. If [useMock] is `true` the [MockCompiler] is used for
@@ -54,8 +55,11 @@
bool minify: false,
bool analyzeAll: false,
bool disableInlining: true,
+ bool trustJSInteropTypeAnnotations: false,
bool useMock: false,
- void check(String generated)}) async {
+ void check(String generatedEntry),
+ bool returnAll: false}) async {
+ OutputCollector outputCollector = returnAll ? new OutputCollector() : null;
if (useMock) {
// TODO(johnniwinther): Remove this when no longer needed by
// `arithmetic_simplication_test.dart`.
@@ -65,7 +69,9 @@
// compiling a method.
disableTypeInference: true,
enableMinification: minify,
- disableInlining: disableInlining);
+ disableInlining: disableInlining,
+ trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,
+ outputProvider: outputCollector);
await compiler.init();
compiler.parseScript(code);
lego.Element element = compiler.mainApp.find(entry);
@@ -89,7 +95,7 @@
if (check != null) {
check(generated);
}
- return generated;
+ return returnAll ? outputCollector.getOutput('', 'js') : generated;
} else {
List<String> options = <String>[
Flags.disableTypeInference];
@@ -102,6 +108,9 @@
if (analyzeAll) {
options.add(Flags.analyzeAll);
}
+ if (trustJSInteropTypeAnnotations) {
+ options.add(Flags.trustJSInteropTypeAnnotations);
+ }
Map<String, String> source;
if (entry != 'main') {
@@ -113,6 +122,7 @@
CompilationResult result = await runCompiler(
memorySourceFiles: source,
options: options,
+ outputProvider: outputCollector,
beforeRun: (compiler) {
if (disableInlining) {
compiler.disableInlining = true;
@@ -126,7 +136,7 @@
if (check != null) {
check(generated);
}
- return generated;
+ return returnAll ? outputCollector.getOutput('', 'js') : generated;
}
}
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index ed4cdeb..b7a65e8 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -56,14 +56,19 @@
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
+check_elements_invariants_test: Slow, Pass, Timeout
deferred_mirrors_test: Pass, Slow
-mirror_final_field_inferrer2_test: Pass, Slow
-check_elements_invariants_test: Slow, Pass
-import_mirrors_test: Slow, Pass
+duplicate_library_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 ]
diff --git a/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart
new file mode 100644
index 0000000..3f38205
--- /dev/null
+++ b/tests/compiler/dart2js/interop_anonymous_unreachable_test.dart
@@ -0,0 +1,177 @@
+// 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 tests.dart2js.interop_anonymous_unreachable_test;
+
+import 'dart:async';
+
+import 'package:test/test.dart';
+import 'compiler_helper.dart';
+
+
+main() {
+ test("unreachable code doesn't crash the compiler", () async {
+ // This test is a regression for Issue #24974
+ String generated = await compile("""
+ import 'package:js/js.dart';
+
+ @JS() @anonymous
+ class UniqueLongNameForTesting_A {
+ external factory UniqueLongNameForTesting_A();
+ }
+ main() {}
+ """, returnAll: true);
+
+ // the code should not be included in the output either.
+ expect(generated, isNot(contains("UniqueLongNameForTesting_A")));
+ });
+
+ group('tree-shaking interop types', () {
+ String program = """
+ import 'package:js/js.dart';
+
+ // reachable and allocated
+ @JS() @anonymous
+ class UniqueLongNameForTesting_A {
+ external bool get x;
+ external UniqueLongNameForTesting_D get d;
+ external UniqueLongNameForTesting_E get e;
+ external factory UniqueLongNameForTesting_A(
+ {UniqueLongNameForTesting_B arg0});
+ }
+
+ // visible through the parameter above, but not used.
+ @JS() @anonymous
+ class UniqueLongNameForTesting_B {
+ external factory UniqueLongNameForTesting_B();
+ }
+
+ // unreachable
+ @JS() @anonymous
+ class UniqueLongNameForTesting_C {
+ external factory UniqueLongNameForTesting_C();
+ }
+
+ // visible and reached through `d`.
+ @JS() @anonymous
+ class UniqueLongNameForTesting_D {
+ external factory UniqueLongNameForTesting_D();
+ }
+
+ // visible through `e`, but not reached.
+ @JS() @anonymous
+ class UniqueLongNameForTesting_E {
+ external factory UniqueLongNameForTesting_E();
+ }
+
+ main() {
+ print(new UniqueLongNameForTesting_A().x);
+ print(new UniqueLongNameForTesting_A().d);
+ }
+ """;
+
+ test('no tree-shaking by default', () async {
+ String generated = await compile(program, returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ expect(generated.contains("UniqueLongNameForTesting_D"), isTrue);
+
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+ expect(generated.contains("UniqueLongNameForTesting_C"), isTrue);
+ expect(generated.contains("UniqueLongNameForTesting_E"), isTrue);
+ });
+
+ test('tree-shake when using flag', () async {
+ String generated = await compile(program,
+ trustJSInteropTypeAnnotations: true,
+ returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ expect(generated.contains("UniqueLongNameForTesting_D"), isTrue);
+
+ expect(generated.contains("UniqueLongNameForTesting_B"), isFalse);
+ expect(generated.contains("UniqueLongNameForTesting_C"), isFalse);
+ expect(generated.contains("UniqueLongNameForTesting_E"), isFalse);
+ });
+ });
+
+ group('tree-shaking other native types', () {
+ String program = """
+ import 'dart:html';
+ import 'package:js/js.dart';
+
+ @JS() @anonymous
+ class UniqueLongNameForTesting_A {
+ external dynamic get x;
+ }
+
+ @JS() @anonymous
+ class UniqueLongNameForTesting_B {
+ external dynamic get y;
+ }
+
+ main() {
+ print(new UniqueLongNameForTesting_A().x);
+ }
+ """;
+
+ test('allocation effect of dynamic excludes native types', () async {
+ String generated = await compile(program, returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ // any js-interop type could be allocated by `get x`
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+ // but we exclude other native types like HTMLAudioElement
+ expect(generated.contains("HTMLAudioElement"), isFalse);
+ });
+
+ test('allocation effect of dynamic excludes native types [flag]', () async {
+ // Trusting types doesn't make a difference.
+ String generated = await compile(program,
+ trustJSInteropTypeAnnotations: true,
+ returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ expect(generated.contains("UniqueLongNameForTesting_B"), isTrue);
+ expect(generated.contains("HTMLAudioElement"), isFalse);
+ });
+
+ test('declared native types are included in allocation effect', () async {
+ String program2 = """
+ import 'dart:html';
+ import 'package:js/js.dart';
+
+ @JS() @anonymous
+ class UniqueLongNameForTesting_A {
+ external AudioElement get x;
+ }
+
+ main() {
+ print(new UniqueLongNameForTesting_A().x is AudioElement);
+ }
+ """;
+
+ String generated = await compile(program2, returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ expect(generated.contains("HTMLAudioElement"), isTrue);
+
+ program2 = """
+ import 'dart:html';
+ import 'package:js/js.dart';
+
+ @JS() @anonymous
+ class UniqueLongNameForTesting_A {
+ external dynamic get x;
+ }
+
+ main() {
+ print(new UniqueLongNameForTesting_A().x is AudioElement);
+ }
+ """;
+
+ generated = await compile(program2, returnAll: true);
+ expect(generated.contains("UniqueLongNameForTesting_A"), isTrue);
+ // This extra check is to make sure that we don't include HTMLAudioElement
+ // just because of the is-check. It is optimized away in this case because
+ // we believe it was never instantiated.
+ expect(generated.contains("HTMLAudioElement"), isFalse);
+ });
+ });
+}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
index be1bd40..38608d0 100644
--- a/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
+++ b/tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart
@@ -247,7 +247,7 @@
""",
r"""
function(x) {
- P.print(V.Foo$().getter$1(123));
+ P.print(V.Foo$().get$getter().call$1(123));
}"""),
];
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart
new file mode 100644
index 0000000..b3f2808
--- /dev/null
+++ b/tests/compiler/dart2js/js_backend_cps_ir_codeUnitAt_test.dart
@@ -0,0 +1,46 @@
+// 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.
+
+// Tests for constant folding and lowering String.codeUnitAt.
+
+library basic_tests;
+
+import 'js_backend_cps_ir.dart';
+
+const List<TestEntry> tests = const [
+
+ // Constant folding.
+ const TestEntry(r"""
+main() {
+ print('A'.codeUnitAt(0));
+}""",r"""
+function() {
+ P.print(65);
+}"""),
+
+
+ // Bounds checking.
+ const TestEntry.forMethod('function(foo)',
+r"""
+foo(s) {
+ var sum = 0;
+ for (int i = 0; i < s.length; i++) sum += s.codeUnitAt(i);
+ return sum;
+}
+main() {
+ print(foo('ABC'));
+ print(foo('Hello'));
+}""",r"""
+function(s) {
+ var v0 = s.length, sum = 0, i = 0;
+ for (; i < v0; sum = sum + s.charCodeAt(i), i = i + 1)
+ ;
+ return sum;
+}"""),
+];
+
+
+void main() {
+ runTests(tests);
+}
diff --git a/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart b/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart
new file mode 100644
index 0000000..873afa8
--- /dev/null
+++ b/tests/compiler/dart2js/js_backend_cps_ir_gvn_test.dart
@@ -0,0 +1,64 @@
+// 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.
+
+// Test that the GVN optimization pass works as expected.
+
+library basic_tests;
+
+import 'js_backend_cps_ir.dart';
+
+const List<TestEntry> tests = const [
+ const TestEntry.forMethod('function(foo)', r"""
+foo(x, list) {
+ var sum = 0;
+ for (int k = 0; k < 10; k++) {
+ // Everything can be hoisted out, except the bounds check and sum += z.
+ var a = x.left.left;
+ var b = x.left.right;
+ var c = x.right.left;
+ var d = x.right.right;
+ var i = a.value + c.value;
+ var j = b.value + d.value;
+ var z = list[i * j] + i;
+ sum += z;
+ }
+ return sum;
+}
+// Use a different class for each level in the tree, so type inference
+// is not confused.
+class Root {
+ Branch left, right;
+ Root(this.left, this.right);
+}
+class Branch {
+ Leaf left, right;
+ Branch(this.left, this.right);
+}
+class Leaf {
+ int value;
+ Leaf(this.value);
+}
+main() {
+ var x1 = new Leaf(1);
+ var x2 = new Leaf(10);
+ var x3 = new Leaf(20);
+ var x4 = new Leaf(-10);
+ var y1 = new Branch(x1, x2);
+ var y2 = new Branch(x3, x4);
+ var z = new Root(y1, y2);
+ print(foo(z, [1,2,3,4,5,6,7,8,9,10]));
+}
+""",r"""
+function(x, list) {
+ var v0 = x.left, a = v0.left, b = v0.right, sum = 0, k = 0, c = (v0 = x.right).left, d = v0.right, i = a.value + c.value, v1 = list[v0 = i * (b.value + d.value)];
+ for (; k < 10; sum = sum + (v1 + i), k = k + 1)
+ if (v0 < 0 || v0 >= 10)
+ return H.ioore(list, v0);
+ return sum;
+}"""),
+];
+
+void main() {
+ runTests(tests);
+}
diff --git a/tests/compiler/dart2js/js_spec_string_test.dart b/tests/compiler/dart2js/js_spec_string_test.dart
index 1481da4..01c9f64 100644
--- a/tests/compiler/dart2js/js_spec_string_test.dart
+++ b/tests/compiler/dart2js/js_spec_string_test.dart
@@ -64,10 +64,11 @@
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 @@
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 @@
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']);
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 9dde5bf..ae06d45 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -79,6 +79,7 @@
// affected by inlining support.
bool disableInlining: true,
bool trustTypeAnnotations: false,
+ bool trustJSInteropTypeAnnotations: false,
bool enableAsyncAwait: false,
int this.expectedWarnings,
int this.expectedErrors,
@@ -98,6 +99,7 @@
emitJavaScript: emitJavaScript,
preserveComments: preserveComments,
trustTypeAnnotations: trustTypeAnnotations,
+ trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations,
diagnosticOptions:
new DiagnosticOptions(showPackageWarnings: true),
outputProvider: new LegacyCompilerOutput(outputProvider)) {
diff --git a/tests/compiler/dart2js/mock_libraries.dart b/tests/compiler/dart2js/mock_libraries.dart
index 9b89db0..1141416 100644
--- a/tests/compiler/dart2js/mock_libraries.dart
+++ b/tests/compiler/dart2js/mock_libraries.dart
@@ -64,10 +64,6 @@
}''',
'LinkedHashMap': r'''
class LinkedHashMap<K, V> implements Map<K, V> {
- factory LinkedHashMap._empty() => null;
- factory LinkedHashMap._literal(elements) => null;
- static _makeEmpty() => null;
- static _makeLiteral(elements) => null;
}''',
'List': r'''
class List<E> extends Iterable<E> {
@@ -113,6 +109,14 @@
import 'dart:_interceptors';
import 'dart:_isolate_helper';
import 'dart:async';
+
+@patch
+class LinkedHashMap<K, V> {
+ factory LinkedHashMap._empty() => null;
+ factory LinkedHashMap._literal(elements) => null;
+ static _makeEmpty() => null;
+ static _makeLiteral(elements) => null;
+}
''';
const Map<String, String> DEFAULT_JS_HELPER_LIBRARY = const <String, String>{
diff --git a/tests/compiler/dart2js/octagon_test.dart b/tests/compiler/dart2js/octagon_test.dart
index 2644c0e..59ea0c0 100644
--- a/tests/compiler/dart2js/octagon_test.dart
+++ b/tests/compiler/dart2js/octagon_test.dart
@@ -233,17 +233,35 @@
}
lower_bounds_check() {
+ setup();
SignedVariable w = octagon.makeVariable(0, 1000);
pushConstraint(w, w, -1);
Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not <= -1');
}
upper_bounds_check() {
+ setup();
SignedVariable w = octagon.makeVariable(0, 1000);
pushConstraint(w.negated, w.negated, -5000);
Expect.isTrue(octagon.isUnsolvable, 'Value in range 0..1000 is not >= 5000');
}
+diamond_graph() {
+ setup();
+ pushConstraint(v1, v2.negated, 10);
+ pushConstraint(v1, v3.negated, 1);
+ pushConstraint(v2, v3.negated, 1);
+ pushConstraint(v2, v4.negated, 2);
+ pushConstraint(v3, v2.negated, 0);
+ pushConstraint(v3, v4.negated, 100);
+ Expect.isTrue(octagon.isSolvable, 'v1 <= v4 + 3');
+ var c = pushConstraint(v4, v1.negated, -4);
+ Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
+ popConstraint(c);
+ pushConstraint(v1.negated, v4, -4); // Check converse constraint.
+ Expect.isTrue(octagon.isUnsolvable, 'v4 <= v1 - 4 should be a contradiction');
+}
+
void main() {
negative_loop1();
negative_loop2();
@@ -261,4 +279,5 @@
contradict2();
lower_bounds_check();
upper_bounds_check();
+ diamond_graph();
}
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index f23b1f1..d552ccd 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -778,7 +778,7 @@
checkReturn('testIsCheck17', intType);
checkReturn('testIsCheck18', typesTask.dynamicType);
checkReturn('testIsCheck19', typesTask.dynamicType);
- checkReturn('testIsCheck20', typesTask.dynamicType.nonNullable());
+ checkReturn('testIsCheck20', interceptorType);
checkReturn('testIsCheck21', typesTask.dynamicType);
checkReturn('testIsCheck22', typesTask.dynamicType);
checkReturn('testIsCheck23', intType);
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
index c7604f7..48bf71b 100644
--- a/tests/compiler/dart2js/size_test.dart
+++ b/tests/compiler/dart2js/size_test.dart
@@ -9,9 +9,9 @@
const String TEST = "main() => [];";
const Map<String, String> DEFAULT_CORELIB_WITH_LIST = const <String, String>{
- 'Object': 'class Object { Object(); }',
+ 'Object': 'class Object { const Object(); }',
'bool': 'class bool {}',
- 'List': 'abstract class List {}',
+ 'List': 'abstract class List<E> {}',
'num': 'class num {}',
'int': 'class int {}',
'double': 'class double {}',
diff --git a/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart b/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart
new file mode 100644
index 0000000..8d3929f
--- /dev/null
+++ b/tests/compiler/dart2js_extra/consistent_codeUnitAt_error_test.dart
@@ -0,0 +1,132 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test that optimized codeUnitAt and slow path codeUnitAt produce the same
+// error.
+
+@NoInline()
+@AssumeDynamic()
+confuse(x) => x;
+
+void check2(String name, name1, f1, name2, f2) {
+ Error trap(part, f) {
+ try {
+ f();
+ } catch (e) {
+ return e;
+ }
+ Expect.fail('should throw: $name.$part');
+ }
+ var e1 = trap(name1, f1);
+ var e2 = trap(name2, f2);
+ var s1 = '$e1';
+ var s2 = '$e2';
+ Expect.equals(s1, s2, '\n $name.$name1: "$s1"\n $name.$name2: "$s2"\n');
+}
+
+void check(String name, f1, f2, [f3, f4]) {
+ check2(name, 'f1', f1, 'f2', f2);
+ if (f3 != null) check2(name, 'f1', f1, 'f3', f3);
+ if (f4 != null) check2(name, 'f1', f1, 'f4', f4);
+}
+
+
+class TooHigh {
+ static f1() {
+ return confuse('AB').codeUnitAt(3); // dynamic receiver.
+ }
+
+ static f2() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ var i = confuse(3);
+ return a.codeUnitAt(i);
+ }
+
+ static f3() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ return a.codeUnitAt(3);
+ }
+
+ static test() {
+ check('TooHigh', f1, f2, f3);
+ }
+}
+
+class Negative {
+ static f1() {
+ return confuse('AB').codeUnitAt(-3); // dynamic receiver.
+ }
+
+ static f2() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ var i = confuse(-3);
+ return a.codeUnitAt(i);
+ }
+
+ static f3() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ var i = confuse(true) ? -3 : 0;
+ return a.codeUnitAt(i);
+ }
+
+ static f4() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ return a.codeUnitAt(-3);
+ }
+
+ static test() {
+ check('Negative', f1, f2, f3, f4);
+ }
+}
+
+class Empty {
+ static f1() {
+ return confuse('').codeUnitAt(0); // dynamic receiver.
+ }
+
+ static f2() {
+ var a = confuse(true) ? '' : 'ABCDE'; // Empty String with unknown length.
+ var i = confuse(true) ? 0 : 1;
+ return a.codeUnitAt(i);
+ }
+
+ static f3() {
+ var a = confuse(true) ? '' : 'ABCDE'; // Empty String with unknown length.
+ return a.codeUnitAt(0);
+ }
+
+ static test() {
+ check('Empty', f1, f2, f3);
+ }
+}
+
+class BadType {
+ static f1() {
+ return confuse('AB').codeUnitAt('a'); // dynamic receiver.
+ }
+
+ static f2() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ var i = confuse('a');
+ return a.codeUnitAt(i);
+ }
+
+ static f3() {
+ var a = confuse(true) ? 'AB' : 'ABCDE'; // String with unknown length.
+ return a.codeUnitAt('a');
+ }
+
+ static test() {
+ check('BadType', f1, f2, f3);
+ }
+}
+
+main() {
+ TooHigh.test();
+ Negative.test();
+ Empty.test();
+ BadType.test();
+}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index cd1f42d..9a04a94 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -10,7 +10,6 @@
no_such_method_test: Fail # Wrong Invocation.memberName.
constant_javascript_semantics4_test: Fail, OK
mirrors_used_closure_test: Fail # Issue 17939
-interop_anonymous_unreachable_test: Crash # Issue 24974
[ $compiler == dart2js && $runtime == jsshell ]
mirror_printer_test: Pass, Slow # Issue 16473
diff --git a/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart b/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart
deleted file mode 100644
index b734491..0000000
--- a/tests/compiler/dart2js_extra/interop_anonymous_unreachable_test.dart
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
-// All rights reserved. Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-import 'package:js/js.dart';
-
-@JS()
-@anonymous
-class A {
- external bool get value;
- external factory A({bool value});
-}
-
-void main() {}
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 2066a92..e83f9d9 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -23,7 +23,6 @@
[ $compiler == dart2js && $cps_ir ]
native_exception_test: RuntimeError # Issue 24421
native_method_inlining_test: RuntimeError # Please triage this failure.
-native_no_such_method_exception3_frog_test: RuntimeError # Please triage this failure.
optimization_hints_test: RuntimeError # Please triage this failure.
subclassing_constructor_1_test: RuntimeError # Please triage this failure.
subclassing_constructor_2_test: RuntimeError # Please triage this failure.
diff --git a/tests/corelib/errors_test.dart b/tests/corelib/errors_test.dart
index edfa761..c980d44 100644
--- a/tests/corelib/errors_test.dart
+++ b/tests/corelib/errors_test.dart
@@ -25,9 +25,9 @@
new ArgumentError.value(42, "foo", "message").toString());
Expect.equals("Invalid argument: message: 42",
new ArgumentError.value(42, null, "message").toString());
- Expect.equals("Invalid argument: Must not be null: null",
+ Expect.equals("Invalid argument(s): Must not be null",
new ArgumentError.notNull().toString());
- Expect.equals("Invalid argument (foo): Must not be null: null",
+ Expect.equals("Invalid argument(s) (foo): Must not be null",
new ArgumentError.notNull("foo").toString());
Expect.equals("RangeError",
diff --git a/tests/corelib/stacktrace_current_test.dart b/tests/corelib/stacktrace_current_test.dart
new file mode 100644
index 0000000..f68ba32
--- /dev/null
+++ b/tests/corelib/stacktrace_current_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:convert" show LineSplitter;
+
+import "package:expect/expect.dart";
+
+void main() {
+ var st0;
+ var st1;
+ // Primitive way to get stack trace,.
+ try { throw 0; } catch (_, s) { st0 = s; }
+ st1 = StackTrace.current;
+
+ var st0s = findMain(st0);
+ var st1s = findMain(st1);
+ // Stack traces are not equal (contains at least a different line number,
+ // and possible different frame numbers).
+ // They are *similar*, so check that they agree on everything but numbers.
+ var digits = new RegExp(r"\d+");
+ Expect.equals(st0s.replaceAll(digits, "0"), st1s.replaceAll(digits, "0"));
+}
+
+String findMain(StackTrace stack) {
+ var string = "$stack";
+ var lines = LineSplitter.split(string).toList();
+ while (lines.isNotEmpty && !lines.first.contains("main")) {
+ lines.removeAt(0);
+ }
+ return lines.join("\n");
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 60180f9..b5f2cf3 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -9,8 +9,8 @@
[ $compiler == none && ($runtime == dartium || $runtime == drt) ]
js_array_test: Skip # Dartium JSInterop failure
-js_typed_interop_test: Skip # Dartium JSInterop failure
-mirrors_js_typed_interop_test: Skip # Dartium JSInterop failure
+mirrors_js_typed_interop_test: Fail # Missing expected failure (Issue 25044)
+js_typed_interop_side_cast_exp_test: Fail, OK # tests dart2js-specific behavior.
cross_domain_iframe_test: RuntimeError # Dartium JSInterop failure
indexeddb_2_test: Fail # Dartium JSInterop failure. Identity preservation on array deferred copy.
@@ -19,7 +19,6 @@
native_gc_test: Skip # Dartium JSInterop failure
transferables_test: RuntimeError # Dartium JSInterop failure
-
[ $compiler == none && ($runtime == drt || $runtime == dartium ) ]
worker_api_test: Fail # Issue 10223
resource_http_test: Fail # Issue 24203
diff --git a/tests/html/js_dart_to_string_test.dart b/tests/html/js_dart_to_string_test.dart
index 5293053..d2c23f4 100644
--- a/tests/html/js_dart_to_string_test.dart
+++ b/tests/html/js_dart_to_string_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
@JS()
-library js_typed_interop_test;
+library js_dart_to_string_test;
import 'dart:html';
diff --git a/tests/html/js_typed_interop_anonymous2_exp_test.dart b/tests/html/js_typed_interop_anonymous2_exp_test.dart
new file mode 100644
index 0000000..baebd03
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous2_exp_test.dart
@@ -0,0 +1,52 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous2, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous2_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+ external factory A({B b});
+
+ external B get b;
+}
+
+@JS() @anonymous
+class B {
+ external factory B({C c});
+
+ external C get c;
+}
+
+@JS() @anonymous
+class C {
+ external factory C();
+}
+
+// D is unreachable, and that is OK
+@JS() @anonymous
+class D {
+ external factory D();
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('simple', () {
+ var b = new B();
+ var a = new A(b: b);
+ expect(a.b, equals(b));
+ expect(b.c, isNull);
+ });
+}
diff --git a/tests/html/js_typed_interop_anonymous2_test.dart b/tests/html/js_typed_interop_anonymous2_test.dart
new file mode 100644
index 0000000..ed0e732
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous2_test.dart
@@ -0,0 +1,48 @@
+// 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 js_typed_interop_anonymous2_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+ external factory A({B b});
+
+ external B get b;
+}
+
+@JS() @anonymous
+class B {
+ external factory B({C c});
+
+ external C get c;
+}
+
+@JS() @anonymous
+class C {
+ external factory C();
+}
+
+// D is unreachable, and that is OK
+@JS() @anonymous
+class D {
+ external factory D();
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('simple', () {
+ var b = new B();
+ var a = new A(b: b);
+ expect(a.b, equals(b));
+ expect(b.c, isNull);
+ });
+}
diff --git a/tests/html/js_typed_interop_anonymous_exp_test.dart b/tests/html/js_typed_interop_anonymous_exp_test.dart
new file mode 100644
index 0000000..40a04aa
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_exp_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+ external factory Literal({int x, String y, num z});
+
+ external int get x;
+ external String get y;
+ external num get z;
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('simple', () {
+ var l = new Literal(x: 3, y: "foo");
+ expect(l.x, equals(3));
+ expect(l.y, equals("foo"));
+ expect(l.z, isNull);
+ });
+}
diff --git a/tests/html/js_typed_interop_anonymous_test.dart b/tests/html/js_typed_interop_anonymous_test.dart
new file mode 100644
index 0000000..b2d1593
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_test.dart
@@ -0,0 +1,32 @@
+// 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 js_typed_interop_anonymous_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+ external factory Literal({int x, String y, num z});
+
+ external int get x;
+ external String get y;
+ external num get z;
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('simple', () {
+ var l = new Literal(x: 3, y: "foo");
+ expect(l.x, equals(3));
+ expect(l.y, equals("foo"));
+ expect(l.z, isNull);
+ });
+}
diff --git a/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart b/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart
new file mode 100644
index 0000000..a4e2c96
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_unreachable_exp_test.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Same test as js_typed_interop_anonymous_unreachable, but using the
+// --experimental-trust-js-interop-type-annotations flag.
+library js_typed_interop_anonymous_unreachable_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+ external factory Literal({int x, String y, num z});
+
+ external int get x;
+ external String get y;
+ external num get z;
+}
+
+main() {
+ useHtmlConfiguration();
+ test('nothing to do', () {
+ // This test is empty, but it is a regression for Issue# 24974: dartjs
+ // would crash trying to compile code that used @anonymous and that was
+ // not reachable from main.
+ });
+}
diff --git a/tests/html/js_typed_interop_anonymous_unreachable_test.dart b/tests/html/js_typed_interop_anonymous_unreachable_test.dart
new file mode 100644
index 0000000..ba8758e
--- /dev/null
+++ b/tests/html/js_typed_interop_anonymous_unreachable_test.dart
@@ -0,0 +1,30 @@
+// 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 js_typed_interop_anonymous_unreachable_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class Literal {
+ external factory Literal({int x, String y, num z});
+
+ external int get x;
+ external String get y;
+ external num get z;
+}
+
+main() {
+ useHtmlConfiguration();
+ test('nothing to do', () {
+ // This test is empty, but it is a regression for Issue# 24974: dartjs
+ // would crash trying to compile code that used @anonymous and that was
+ // not reachable from main.
+ });
+}
diff --git a/tests/html/js_typed_interop_side_cast_exp_test.dart b/tests/html/js_typed_interop_side_cast_exp_test.dart
new file mode 100644
index 0000000..6fd929a
--- /dev/null
+++ b/tests/html/js_typed_interop_side_cast_exp_test.dart
@@ -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.
+//
+// SharedOptions=--experimental-trust-js-interop-type-annotations
+
+// Similar test to js_typed_interop_side_cast, but because we are using the
+// --experimental-trust-js-interop-type-annotations flag, we test a slighly
+// different behavior.
+library js_typed_interop_side_cast_exp_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+ external int get x;
+ external factory A({int x});
+}
+
+@JS() @anonymous
+class B {
+ external int get x;
+ external factory B({int x});
+}
+
+@JS() @anonymous
+class C {
+ external int get x;
+ external factory C({int x});
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('side-casts work for reachable types', () {
+ new C(x: 3); // make C reachable
+ var a = new A(x: 3);
+ expect(a is C, isTrue);
+ C c = a;
+ expect(c.x, equals(3));
+ });
+
+ // Note: this test would fail without the experimental flag.
+ test('side-casts do not work for unreachable types', () {
+ var a = new A(x: 3);
+ expect(a is B, isFalse);
+ });
+}
diff --git a/tests/html/js_typed_interop_side_cast_test.dart b/tests/html/js_typed_interop_side_cast_test.dart
new file mode 100644
index 0000000..d50e1ac
--- /dev/null
+++ b/tests/html/js_typed_interop_side_cast_test.dart
@@ -0,0 +1,47 @@
+// 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 js_typed_interop_anonymous2_test;
+
+import 'dart:html';
+import 'dart:js' as js;
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+
+@JS() @anonymous
+class A {
+ external int get x;
+ external factory A({int x});
+}
+
+@JS() @anonymous
+class C {
+ external int get x;
+ external factory C({int x});
+}
+
+@JS() @anonymous
+class B {
+ external int get x;
+ external factory B({int x});
+}
+
+main() {
+ useHtmlConfiguration();
+
+ test('side-casts work for reachable types', () {
+ new C(x: 3); // make C reachable
+ var a = new A(x: 3);
+ expect(a is C, isTrue);
+ C c = a;
+ expect(c.x, equals(3));
+ });
+
+ test('side-casts work for otherwise unreachable types', () {
+ var a = new A(x: 3);
+ expect(a is B, isTrue);
+ });
+}
diff --git a/tests/isolate/isolate_import_test.dart b/tests/isolate/isolate_import_test.dart
index 5fa0f32..8d9f6a1 100644
--- a/tests/isolate/isolate_import_test.dart
+++ b/tests/isolate/isolate_import_test.dart
@@ -7,10 +7,11 @@
/* /// 01: runtime error, static type warning
import 'dart:isolate';
*/ /// 01: continued
+import 'package:async_helper/async_helper.dart';
void entry(msg) {}
main() {
- Isolate.spawn(entry, null);
+ asyncStart();
+ Isolate.spawn(entry, null).whenComplete(asyncEnd);
}
-
diff --git a/tests/isolate/issue_21398_parent_isolate1_test.dart b/tests/isolate/issue_21398_parent_isolate1_test.dart
index 1c3aeb8..6f036bd 100644
--- a/tests/isolate/issue_21398_parent_isolate1_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate1_test.dart
@@ -10,6 +10,7 @@
import 'dart:isolate';
import 'dart:async';
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
class FromMainIsolate {
String toString() => 'from main isolate';
@@ -25,6 +26,7 @@
Expect.isTrue(msg is FromMainIsolate);
Expect.equals(10, msg.fld);
receivePort.close();
+ sendPort.send("done");
},
onError: (e) => print('$e')
);
@@ -57,37 +59,44 @@
// create a receivePort and send it's sendPort back and then it will just
// sit there listening for a message from the second isolate spawned
// using spawnFunction.
- Isolate.spawn(func1Child, [receive1.sendPort]).then(
+ asyncStart();
+ return Isolate.spawn(func1Child, [receive1.sendPort]).then(
(isolate) {
receive1.listen(
(msg) {
- Expect.isTrue(msg is SendPort);
- spawnFunctionIsolate1SendPort = msg;
- receive1.close();
+ if (msg is SendPort) {
+ spawnFunctionIsolate1SendPort = msg;
- // Now spawn the second isolate using spawnFunction, this isolate
- // will create a receivePort and send it's sendPort back and then
- // wait for the third isolate spawned using spawnUri to send it
- // a sendPort to which it will try and send a non "literal-like"
- // object.
- Isolate.spawn(func2Child, [receive2.sendPort]).then(
- (isolate) {
- receive2.listen(
- (msg) {
- spawnFunctionIsolate2SendPort = msg;
- receive2.close();
+ // Now spawn the second isolate using spawnFunction, this isolate
+ // will create a receivePort and send it's sendPort back and then
+ // wait for the third isolate spawned using spawnUri to send it
+ // a sendPort to which it will try and send a non "literal-like"
+ // object.
+ Isolate.spawn(func2Child, [receive2.sendPort]).then(
+ (isolate) {
+ receive2.listen(
+ (msg) {
+ spawnFunctionIsolate2SendPort = msg;
+ receive2.close();
- // Now spawn an isolate using spawnUri and send these send
- // ports over to it. This isolate will send one of the
- // sendports over to the other.
- Isolate.spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
- [spawnFunctionIsolate1SendPort,
- spawnFunctionIsolate2SendPort], "no-msg");
- },
- onError: (e) => print('$e')
- );
- }
- );
+ // Now spawn an isolate using spawnUri and send these send
+ // ports over to it. This isolate will send one of the
+ // sendports over to the other.
+ Isolate
+ .spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
+ [spawnFunctionIsolate1SendPort,
+ spawnFunctionIsolate2SendPort], "no-msg");
+ },
+ onError: (e) => print('$e')
+ );
+ }
+ );
+ } else if (msg == "done") {
+ receive1.close();
+ asyncEnd();
+ } else {
+ Expect.fail("Invalid message received: $msg");
+ }
},
onError: (e) => print('$e')
);
@@ -105,6 +114,7 @@
Expect.isTrue(msg is String);
Expect.equals("Invalid Argument(s).", msg);
receivePort.close();
+ sendPort.send("done");
},
onError: (e) => print('$e')
);
@@ -122,13 +132,13 @@
// create a receivePort and send it's sendPort back and then it will just
// sit there listening for a message from the second isolate spawned
// using spawnFunction.
+ asyncStart();
Isolate.spawn(uriChild, [receive1.sendPort]).then(
(isolate) {
receive1.listen(
(msg) {
- Expect.isTrue(msg is SendPort);
- spawnFunctionIsolateSendPort = msg;
- receive1.close();
+ if (msg is SendPort) {
+ spawnFunctionIsolateSendPort = msg;
// Now spawn the second isolate using spawnUri, this isolate
// will create a receivePort and send it's sendPort back and then
@@ -149,12 +159,18 @@
// sendports over to the other.
Isolate.spawnUri(Uri.parse('issue_21398_child_isolate1.dart'),
[spawnFunctionIsolateSendPort,
- spawnUriIsolateSendPort], "no-msg");
+ spawnUriIsolateSendPort], "no-msg");
},
onError: (e) => print('$e')
);
}
);
+ } else if (msg == "done") {
+ receive1.close();
+ asyncEnd();
+ } else {
+ Expect.fail("Invalid message received: $msg");
+ }
},
onError: (e) => print('$e')
);
diff --git a/tests/isolate/issue_21398_parent_isolate2_test.dart b/tests/isolate/issue_21398_parent_isolate2_test.dart
index 92754fd..da94b56 100644
--- a/tests/isolate/issue_21398_parent_isolate2_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate2_test.dart
@@ -9,6 +9,7 @@
import 'dart:isolate';
import 'dart:async';
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
import "deferred_loaded_lib.dart" deferred as lib;
@@ -27,6 +28,7 @@
void helperFunction() {
var receivePort = new ReceivePort();
+ asyncStart();
// Spawn an isolate using spawnFunction.
Isolate.spawn(funcChild, [receivePort.sendPort]).then(
@@ -36,12 +38,14 @@
// We don't expect to receive any valid messages.
Expect.fail("We don't expect to receive any valid messages");
receivePort.close();
+ asyncEnd();
},
onError: (e) {
// We don't expect to receive any error messages, per spec listen
// does not receive an error object.
Expect.fail("We don't expect to receive any error messages");
receivePort.close();
+ asyncEnd();
}
);
}
diff --git a/tests/isolate/issue_21398_parent_isolate_test.dart b/tests/isolate/issue_21398_parent_isolate_test.dart
index fb4b0fb..76e7e0d 100644
--- a/tests/isolate/issue_21398_parent_isolate_test.dart
+++ b/tests/isolate/issue_21398_parent_isolate_test.dart
@@ -9,6 +9,7 @@
import 'dart:isolate';
import 'dart:async';
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
class FromMainIsolate {
String toString() => 'from main isolate';
@@ -29,13 +30,16 @@
// First spawn an isolate using spawnURI and have it
// send back a "non-literal" like object.
+ asyncStart();
Isolate.spawnUri(Uri.parse('issue_21398_child_isolate.dart'),
[],
[new FromMainIsolate(), receive1.sendPort]).catchError(
(error) {
Expect.isTrue(error is ArgumentError);
+ asyncEnd();
}
);
+ asyncStart();
Isolate.spawnUri(Uri.parse('issue_21398_child_isolate.dart'),
[],
receive1.sendPort).then(
@@ -44,6 +48,7 @@
(msg) {
Expect.stringEquals(msg, "Invalid Argument(s).");
receive1.close();
+ asyncEnd();
},
onError: (e) => print('$e')
);
@@ -53,7 +58,8 @@
// Now spawn an isolate using spawnFunction and send it a "non-literal"
// like object and also have the child isolate send back a "non-literal"
// like object.
- Isolate.spawn(funcChild,
+ asyncStart();
+ Isolate.spawn(funcChild,
[new FromMainIsolate(), receive2.sendPort]).then(
(isolate) {
receive2.listen(
@@ -61,6 +67,7 @@
Expect.isTrue(msg is FromMainIsolate);
Expect.equals(10, msg.fld);
receive2.close();
+ asyncEnd();
},
onError: (e) => print('$e')
);
diff --git a/tests/isolate/message_enum_test.dart b/tests/isolate/message_enum_test.dart
index 7dbaec3..b06dfc3 100644
--- a/tests/isolate/message_enum_test.dart
+++ b/tests/isolate/message_enum_test.dart
@@ -5,6 +5,7 @@
// SharedOptions=--enable-enum
import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
import "dart:isolate";
enum Foo { BAR, BAZ }
@@ -18,7 +19,8 @@
Expect.equals(42, map[key]);
p.close();
});
- Isolate.spawn(sendIt, p.sendPort);
+ asyncStart();
+ Isolate.spawn(sendIt, p.sendPort).whenComplete(asyncEnd);
}
void sendIt(port) {
diff --git a/tests/language/abstract_beats_arguments_test.dart b/tests/language/abstract_beats_arguments_test.dart
new file mode 100644
index 0000000..9fa33e2
--- /dev/null
+++ b/tests/language/abstract_beats_arguments_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// When an instantiation of an abstract class has the wrong arguments, an
+// AbstractClassInstantiationError is thrown, not a NoSuchMethodError.
+
+abstract class A {
+ A() { }
+}
+
+class B {
+ B() { }
+}
+
+bool isAbstractClassInstantiationError(e) =>
+ e is AbstractClassInstantiationError;
+
+bool isNoSuchMethodError(e) => e is NoSuchMethodError;
+
+void main() {
+ Expect.throws(() => new A(), isAbstractClassInstantiationError);
+
+ Expect.throws(() => new B(1), isNoSuchMethodError);
+ Expect.throws(() => new A(1), isAbstractClassInstantiationError);
+}
diff --git a/tests/language/issue23244_test.dart b/tests/language/issue23244_test.dart
index b155769..f8a3f32 100644
--- a/tests/language/issue23244_test.dart
+++ b/tests/language/issue23244_test.dart
@@ -5,6 +5,7 @@
// Regression test case for http://dartbug.com/23244
import 'dart:async';
import 'dart:isolate';
+import 'package:async_helper/async_helper.dart';
enum Fisk {
torsk,
@@ -27,6 +28,7 @@
main() async {
var port = new ReceivePort();
+ asyncStart();
await Isolate.spawn(isolate1, port.sendPort);
Completer completer1 = new Completer();
port.listen((message) {
@@ -53,6 +55,7 @@
port.close();
expectTorsk(message[0]);
expectTorsk(message[1]);
+ asyncEnd();
});
}
@@ -61,4 +64,3 @@
throw "$fisk isn't a ${Fisk.torsk}";
}
}
-
diff --git a/tests/language/language.status b/tests/language/language.status
index c2d3f88..8c5eb92 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -96,8 +96,8 @@
[ $compiler == none && $runtime == vm && ( $arch == simarm || $arch == arm || $arch == simarmv5te || $arch == armv5te || $arch == simarm64 || $arch == arm64 || $arch == simmips || $arch == mips) ]
vm/load_to_load_unaligned_forwarding_vm_test: Pass, Crash # Unaligned offset. Issue 22151
-[ $compiler == none && ( $runtime == dartium || $runtime == drt ) ]
-issue23244_test: Fail # Can't run spawnFunction on dartium.
+[ $compiler == none && $runtime == dartium ]
+issue23244_test: Fail # Issue 23244
[ $compiler == none && ($runtime == vm || $runtime == drt || $runtime == dartium) && $arch == ia32 ]
vm/regress_24517_test: Pass, Fail # Issue 24517.
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index a51dda3..27be7e0 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -187,6 +187,7 @@
empty_block_case_test: StaticWarning # Test Issue 18701
error_stacktrace_test: StaticWarning # Test Issue 18702
+abstract_beats_arguments_test: StaticWarning
const_counter_negative_test: CompileTimeError
const_optional_args_negative_test: CompileTimeError
constructor_redirect1_negative_test: CompileTimeError
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 13c5598..1767b22 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -224,7 +224,7 @@
generic_field_mixin5_test: Crash # Issue 18651
many_method_calls_test: Crash # Stack overflow in HGraphVisitor.visitPostDominatorTree.visitBasicBlockAndSuccessors
-[ $compiler == dart2js && ($runtime == d8 || $runtime == jsshell) ]
+[ $compiler == dart2js ]
issue23244_test: RuntimeError # 23244
[ $compiler == dart2js && $cps_ir ]
@@ -273,6 +273,7 @@
await_for_cancel_test: Crash # (await for(var x in controller.stream){for(int j=0;j<10;j++ ){if(j==5)continue outer;}}): await for
await_for_test: Crash # (await for(var x in infiniteStream()){i++ ;if(i>10)break;t4.record(x);}): await for
await_for_use_local_test: Crash # (await for(var v in s){accum+= v;}): await for
+call_closurization_test: RuntimeError # Bad type inference for ".call" tear-off.
cha_deopt1_test: Crash # (d.make_u()): deferred access is not implemented
cha_deopt2_test: Crash # (d.make_u()): deferred access is not implemented
cha_deopt3_test: Crash # (d.make_u()): deferred access is not implemented
@@ -333,16 +334,12 @@
infinite_switch_label_test: Crash # (switch (target){l0:... continue to a labeled switch case
instanceof2_test: RuntimeError # Please triage this failure.
instanceof4_test/01: RuntimeError # Please triage this failure.
-invocation_mirror_invoke_on_test: RuntimeError # Please triage this failure.
invocation_mirror_test: Crash # (super[37]=42): visitUnresolvedSuperIndexSet
issue_1751477_test: RuntimeError # O.loadLibrary is not a function
list_is_test: RuntimeError # Please triage this failure.
list_test: RuntimeError # Please triage this failure.
many_generic_instanceof_test: RuntimeError # Please triage this failure.
-many_overridden_no_such_method_test: RuntimeError # Please triage this failure.
nested_switch_label_test: Crash # (switch (target){out... continue to a labeled switch case
-no_such_method_test: RuntimeError # Please triage this failure.
-overridden_no_such_method_test: RuntimeError # Please triage this failure.
regress_22443_test: RuntimeError # M.loadLibrary is not a function
regress_23408_test: RuntimeError # G.loadLibrary is not a function
regress_23500_test/01: Crash # (await for(var c in new Stream.fromIterable([] )){}): await for
diff --git a/tests/language/stacktrace_test.dart b/tests/language/stacktrace_test.dart
index e39f151..7ad6eee 100644
--- a/tests/language/stacktrace_test.dart
+++ b/tests/language/stacktrace_test.dart
@@ -1,4 +1,3 @@
-
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
diff --git a/tests/language/vm/optimized_guarded_field_isolates_test.dart b/tests/language/vm/optimized_guarded_field_isolates_test.dart
index fc5e915..a150656 100644
--- a/tests/language/vm/optimized_guarded_field_isolates_test.dart
+++ b/tests/language/vm/optimized_guarded_field_isolates_test.dart
@@ -9,6 +9,7 @@
import "dart:isolate";
import "dart:async";
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
class A {
A(this.a);
@@ -29,6 +30,7 @@
test_field_type() {
var receive_port = new ReceivePort();
+ asyncStart();
Future<Isolate> isolate = Isolate.spawn(f1, receive_port.sendPort);
B b = new B(1, 2);
for (var i = 0; i < 200; i++) { test_b(b); }
@@ -37,6 +39,7 @@
item.then((B value) {
Expect.equals("foobar", test_b(value));
receive_port.close();
+ asyncEnd();
});
}
@@ -53,6 +56,7 @@
test_list_length() {
var receive_port = new ReceivePort();
+ asyncStart();
Future<Isolate> isolate = Isolate.spawn(f2, receive_port.sendPort);
C c = new C(new List(10000));
for (var i = 0; i < 200; i++) { test_c(c); }
@@ -61,6 +65,7 @@
item.then((C value) {
Expect.throws(() => test_c(value), (e) => e is RangeError);
receive_port.close();
+ asyncEnd();
});
}
diff --git a/tests/language/vm/precompiled_static_initializer_test.dart b/tests/language/vm/precompiled_static_initializer_test.dart
new file mode 100644
index 0000000..195e07d
--- /dev/null
+++ b/tests/language/vm/precompiled_static_initializer_test.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test optimizations with static fields with precompilation.
+// VMOptions=--inlining-hotness=0
+
+import 'package:expect/expect.dart';
+
+init() => 123;
+
+final a = init();
+
+main() {
+ var s = 0;
+ for (var i = 0; i < 10; i++) {
+ s += a;
+ }
+ Expect.equals(10 * 123, s);
+}
diff --git a/tests/language/vm/type_propagation_test.dart b/tests/language/vm/type_propagation_test.dart
new file mode 100644
index 0000000..2783654
--- /dev/null
+++ b/tests/language/vm/type_propagation_test.dart
@@ -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);
+}
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 2c983c3..079fa14 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -347,8 +347,6 @@
mirrors/deferred_mirrors_metadata_test: RuntimeError # U.loadLibrary is not a function
mirrors/deferred_mirrors_metatarget_test: RuntimeError # X.loadLibrary is not a function
mirrors/deferred_mirrors_update_test: RuntimeError # U.loadLibrary is not a function
-mirrors/delegate_call_through_getter_test: RuntimeError # Please triage this failure.
-mirrors/delegate_test: RuntimeError # Please triage this failure.
mirrors/library_enumeration_deferred_loading_test: RuntimeError # L.loadLibrary is not a function
mirrors/symbol_validation_test/none: RuntimeError # Please triage this failure.
mirrors/typedef_deferred_library_test: RuntimeError # G.loadLibrary is not a function
diff --git a/tests/standalone/coverage_test.dart b/tests/standalone/coverage_test.dart
deleted file mode 100644
index 1ec4af4..0000000
--- a/tests/standalone/coverage_test.dart
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs the script tools/coverage.dart
-// and verifies that the coverage tool produces its expected output.
-// This test is mainly here to ensure that the coverage tool compiles and
-// runs.
-
-import "dart:async";
-import "dart:convert";
-import "dart:io";
-
-import "package:path/path.dart";
-
-// Coverage tool script relative to the path of this test.
-var coverageToolScript = "../../tools/coverage.dart";
-
-// Coverage target script relative to this test.
-var coverageTargetScript = "../language/hello_dart_test.dart";
-var targPath;
-
-Process coverageToolProcess;
-List sourceLines;
-int nextLineToMatch = 0;
-
-void onCoverageOutput(String line) {
- print("COV: $line");
- if (nextLineToMatch < sourceLines.length) {
- if (line.endsWith("|" + sourceLines[nextLineToMatch])) {
- nextLineToMatch++;
- }
- }
-}
-
-bool checkExitCode(exitCode) {
- var pid = coverageToolProcess.pid;
- print("Coverage tool process (pid $pid) terminated with "
- "exit code $exitCode.");
- return exitCode == 0;
-}
-
-void checkSuccess() {
- if (nextLineToMatch == sourceLines.length) {
- print("Successfully matched all lines of '$targPath'");
- } else {
- print("Error: could not match all source code lines of '$targPath'");
- exit(-1);
- }
-}
-
-void main() {
- // Compute paths for coverage tool and coverage target relative
- // the the path of this script.
- var scriptPath = dirname(Platform.script.toFilePath());
- var toolPath = normalize(join(scriptPath, coverageToolScript));
- targPath = normalize(join(scriptPath, coverageTargetScript));
-
- sourceLines = new File(targPath).readAsLinesSync();
- assert(sourceLines != null);
-
- var processOpts = [ "--compile_all", toolPath, targPath ];
-
- Process.start(Platform.executable, processOpts).then((Process process) {
- coverageToolProcess = process;
- coverageToolProcess.stdin.close();
- var stdoutStringStream = coverageToolProcess.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
-
- var stderrStringStream = coverageToolProcess.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
-
- // Wait for 3 future events: stdout and stderr streams of the coverage
- // tool process closed, and coverage tool process terminated.
- var futures = [];
- var subscription = stdoutStringStream.listen(onCoverageOutput);
- futures.add(subscription.asFuture(true));
- subscription = stderrStringStream.listen(onCoverageOutput);
- futures.add(subscription.asFuture(true));
- futures.add(coverageToolProcess.exitCode.then(checkExitCode));
- Future.wait(futures).then((results) {
- checkSuccess();
- if (results.contains(false)) exit(-1);
- });
- });
-}
diff --git a/tests/standalone/debugger/basic_debugger_test.dart b/tests/standalone/debugger/basic_debugger_test.dart
deleted file mode 100644
index 9dfded6..0000000
--- a/tests/standalone/debugger/basic_debugger_test.dart
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
- var localStr = "foo";
- int localInt = 1;
- double localDouble = 1.1;
-
- print(x);
-}
-
-bam(a) => bar(a);
-
-foo(i) {
- bar("baz");
- print(i);
-}
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- foo(42);
- bam("bam");
- print("Hello again");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- Step(),
- MatchFrame(0, "main"), // Should still be in "main".
- SetBreakpoint(19), // Set breakpoint a line 19, in function bar.
- Resume(),
- MatchFrames(["bar", "foo", "main"]),
- MatchFrame(1, "foo"),
- MatchLocals({"localStr": '"foo"', "localInt": "1", "localDouble": "1.1",
- "x": '"baz"'}),
- SetBreakpoint(22), // Set breakpoint a line 22, in function bam.
- Resume(),
- MatchFrames(["bam", "main"]),
- Resume(),
- MatchFrames(["bar", "bam", "main"]),
- Resume(),
-];
diff --git a/tests/standalone/debugger/break_at_equals_test.dart b/tests/standalone/debugger/break_at_equals_test.dart
deleted file mode 100644
index 5000e6d..0000000
--- a/tests/standalone/debugger/break_at_equals_test.dart
+++ /dev/null
@@ -1,52 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-class MyClass {
- operator ==(other) {
- print(other);
- return true; // Breakpoint #3.
- }
-}
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- var a = new MyClass();
- var b = null;
- a == b; // Breakpoint #1.
- print("after 1");
- b = 123;
- a == b; // Breakpoint #2.
- print("after 2");
- a == null; // Breakpoint #4.
- print("after 4");
- if (null == a) {
- throw "unreachable";
- }
- print("ok");
-}
-
-// Checks that debugger can stop at calls to == even if one
-// of the operands is null.
-
-var testScript = [
- MatchFrames(["main"]),
- MatchLine(14),
- SetBreakpoint(18),
- SetBreakpoint(21),
- SetBreakpoint(10),
- SetBreakpoint(23),
- Resume(),
- MatchFrames(["main"]),
- MatchLine(18), // At breakpoint #1.
- Resume(),
- MatchLine(21), // At breakpoint #2; didn't hit breakpoint in MyClass.==.
- Resume(),
- MatchFrames(["MyClass.==", "main"]),
- MatchLine(10), // At breakpoint #3 in MyClass.==.
- Resume(),
- MatchLine(23), // At breakpoint #4.
- Resume()
-];
diff --git a/tests/standalone/debugger/breakpoint_resolved_test.dart b/tests/standalone/debugger/breakpoint_resolved_test.dart
deleted file mode 100644
index 14c2827..0000000
--- a/tests/standalone/debugger/breakpoint_resolved_test.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
-
- bar();
-
- print("Hello from debuggee");
-}
-
-bar() {
- // Attempt to set breakpoint in this empty line does not
- // result in a resolved breakpoint.
- print("bar");
-}
-
-var testScript = [
- MatchFrame(0, "main"),
- SetBreakpoint(10),
- SetBreakpoint(12),
- SetBreakpoint(16),
- Resume(),
- MatchFrame(0, "main"),
- Resume(), // Next breakpoint expected in main, when bar() returns.
- MatchFrame(0, "main"),
- // Only two breakpoint resolved events expected.
- ExpectEvent("breakpointResolved", {"breakpointId": 2}),
- ExpectEvent("breakpointResolved", {"breakpointId": 3}),
- Resume(),
-];
diff --git a/tests/standalone/debugger/closure_bp_test.dart b/tests/standalone/debugger/closure_bp_test.dart
deleted file mode 100644
index 2eb2bfd..0000000
--- a/tests/standalone/debugger/closure_bp_test.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
- print(x);
-}
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- [1,2].forEach(bar); // Causes implicit closure of bar to be compiled.
- print("stop here"); // Stop here and set breakpoint in bar.
- [3,4].forEach(bar); // Call bar closure and observe breakpoints being hit.
- print("done");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(22), // Set breakpoint a line 22, after bar closure is compiled.
- Resume(),
- MatchFrame(0, "main"), // Should be at line 22 in main.
- MatchLine(22),
- SetBreakpoint(15), // Set breakpoint in function bar. Bar has not been called
- // through a regular function call at this point, only
- // through a closure from forEach().
- Resume(),
- MatchFrames(["bar", "forEach", "main"]), // Should be in closure function now.
- MatchLine(15),
- MatchLocals({"x": "3"}),
- Resume(),
- MatchFrames(["bar", "forEach", "main"]), // Should be in closure function now.
- MatchLine(15),
- MatchLocals({"x": "4"}),
- Resume(),
-];
diff --git a/tests/standalone/debugger/closure_debugger_test.dart b/tests/standalone/debugger/closure_debugger_test.dart
deleted file mode 100644
index 7562a8c..0000000
--- a/tests/standalone/debugger/closure_debugger_test.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-bar(x) {
- print(x);
-}
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- var f = bar;
- f("closure call");
- bar(12);
- var a = new A();
- for (var i = 0; i < 2; ++i) {
- a.foo(i);
- }
-}
-
-class A {
- A() {
- foo =
- (x) => print(x);
- }
- var foo;
-}
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(22), // Set breakpoint a line 22, at the closure call.
- Resume(),
- MatchFrame(0, "main"), // Should be at closure call.
- StepInto(),
- MatchFrames(["bar", "main"]), // Should be in closure function now.
- StepOut(),
- MatchFrame(0, "main"), // Back in main, before static call to bar().
- SetBreakpoint(15), // Breakpoint in bar();
- Resume(),
- MatchFrames(["bar", "main"]),
- SetBreakpoint(26), // Breakpoint in main() at a.field(i).
- SetBreakpoint(33), // Breakpoint in closure.
- Resume(),
- MatchFrame(0, "main"), // Should be in main().
- MatchLocals({"i": "0"}),
- StepInto(),
- StepInto(),
- MatchFrames(["A.<anonymous closure>", "main"]), // In closure function.
- Resume(),
- MatchFrame(0, "main"), // Back in main().
- MatchLocals({"i": "1"}),
- Resume(),
- MatchFrames(["A.<anonymous closure>", "main"]), // In closure function.
- Resume()
-];
diff --git a/tests/standalone/debugger/debug_lib.dart b/tests/standalone/debugger/debug_lib.dart
deleted file mode 100644
index 92a0d10..0000000
--- a/tests/standalone/debugger/debug_lib.dart
+++ /dev/null
@@ -1,749 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Library used by debugger wire protocol tests (standalone VM debugging).
-
-library DartDebugger;
-
-import "dart:async";
-import "dart:convert";
-import "dart:io";
-import "dart:math";
-
-// Whether or not to print the debugger wire messages on the console.
-var verboseWire = false;
-
-// Class to buffer wire protocol data from debug target and
-// break it down to individual json messages.
-class JsonBuffer {
- String buffer = null;
-
- append(String s) {
- if (buffer == null || buffer.length == 0) {
- buffer = s;
- } else {
- buffer += s;
- }
- }
-
- String getNextMessage() {
- if (buffer == null) return null;
- int msgLen = objectLength();
- if (msgLen == 0) return null;
- String msg = null;
- if (msgLen == buffer.length) {
- msg = buffer;
- buffer = null;
- } else {
- assert(msgLen < buffer.length);
- msg = buffer.substring(0, msgLen);
- buffer = buffer.substring(msgLen);
- }
- return msg;
- }
-
- bool haveGarbage() {
- if (buffer == null || buffer.length == 0) return false;
- var i = 0, char = " ";
- while (i < buffer.length) {
- char = buffer[i];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- i++;
- }
- if (i >= buffer.length) {
- return false;
- } else {
- return char != "{";
- }
- }
-
- // Returns the character length of the next json message in the
- // buffer, or 0 if there is only a partial message in the buffer.
- // The object value must start with '{' and continues to the
- // matching '}'. No attempt is made to otherwise validate the contents
- // as JSON. If it is invalid, a later JSON.decode() will fail.
- int objectLength() {
- int skipWhitespace(int index) {
- while (index < buffer.length) {
- String char = buffer[index];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- index++;
- }
- return index;
- }
- int skipString(int index) {
- assert(buffer[index - 1] == '"');
- while (index < buffer.length) {
- String char = buffer[index];
- if (char == '"') return index + 1;
- if (char == r'\') index++;
- if (index == buffer.length) return index;
- index++;
- }
- return index;
- }
- int index = 0;
- index = skipWhitespace(index);
- // Bail out if the first non-whitespace character isn't '{'.
- if (index == buffer.length || buffer[index] != '{') return 0;
- int nesting = 0;
- while (index < buffer.length) {
- String char = buffer[index++];
- if (char == '{') {
- nesting++;
- } else if (char == '}') {
- nesting--;
- if (nesting == 0) return index;
- } else if (char == '"') {
- // Strings can contain braces. Skip their content.
- index = skipString(index);
- }
- }
- return 0;
- }
-}
-
-
-getJsonValue(Map jsonMsg, String path) {
- List properties = path.split(new RegExp(":"));
- assert(properties.length >= 1);
- var node = jsonMsg;
- for (int i = 0; i < properties.length; i++) {
- if (node == null) return null;
- String property = properties[i];
- var index = null;
- if (property.endsWith("]")) {
- var bracketPos = property.lastIndexOf("[");
- if (bracketPos <= 0) return null;
- var indexStr = property.substring(bracketPos + 1, property.length - 1);
- try {
- index = int.parse(indexStr);
- } on FormatException {
- print("$indexStr is not a valid array index");
- return null;
- }
- property = property.substring(0, bracketPos);
- }
- if (node is Map) {
- node = node[property];
- } else {
- return null;
- }
- if (index != null) {
- if (node is List && node.length > index) {
- node = node[index];
- } else {
- return null;
- }
- }
- }
- return node;
-}
-
-
-// Returns true if [template] is a subset of [map].
-bool matchMaps(Map template, Map msg) {
- bool isMatch = true;
- template.forEach((k, v) {
- if (msg.containsKey(k)) {
- var receivedValue = msg[k];
- if ((v is Map) && (receivedValue is Map)) {
- if (!matchMaps(v, receivedValue)) isMatch = false;
- } else if (v == null) {
- // null in the template matches everything.
- } else if (v != receivedValue) {
- isMatch = false;
- }
- } else {
- isMatch = false;
- }
- });
- return isMatch;
-}
-
-
-class Command {
- var template;
-
- void send(Debugger debugger) {
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- Map response = debugger.currentMessage;
- var id = template["id"];
- assert(id != null && id >= 0);
- if (response["id"] != id) {
- debugger.error("Error: expected messaged id $id but got ${response["id"]}.");
- }
- }
-}
-
-class GetLineTableCmd extends Command {
- GetLineTableCmd() {
- template = {"id": 0,
- "command": "getLineNumberTable",
- "params": {"isolateId": 0, "libraryId": 0, "url": ""}};
- }
-
- void send(Debugger debugger) {
- assert(debugger.scriptUrl != null);
- template["params"]["url"] = debugger.scriptUrl;
- template["params"]["libraryId"] = debugger.libraryId;
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- List<List<int>> table = getJsonValue(debugger.currentMessage, "result:lines");
- debugger.tokenToLine = {};
- for (var line in table) {
- // Each entry begins with a line number...
- var lineNumber = line[0];
- for (var pos = 1; pos < line.length; pos += 2) {
- // ...and is followed by (token offset, col number) pairs.
- var tokenOffset = line[pos];
- debugger.tokenToLine[tokenOffset] = lineNumber;
- }
- }
- }
-}
-
-
-class LineMatcher extends Command {
- int expectedLineNumber;
-
- LineMatcher(this.expectedLineNumber) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- assert(debugger.tokenToLine != null);
- super.matchResponse(debugger);
- var msg = debugger.currentMessage;
- List frames = getJsonValue(msg, "result:callFrames");
- assert(frames != null);
- var tokenOffset = frames[0]["location"]["tokenOffset"];
- assert(tokenOffset != null);
- var lineNumber = debugger.tokenToLine[tokenOffset];
- assert(lineNumber != null);
- if (expectedLineNumber != lineNumber) {
- debugger.error("Error: expected pause at line $expectedLineNumber "
- "but reported line is $lineNumber.");
- return;
- }
- print("Matched line number $lineNumber");
- }
-}
-
-MatchLine(lineNumber) {
- return new LineMatcher(lineNumber);
-}
-
-
-class FrameMatcher extends Command {
- int frameIndex;
- List<String> functionNames;
- bool exactMatch;
-
- FrameMatcher(this.frameIndex, this.functionNames, this.exactMatch) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- var msg = debugger.currentMessage;
- List frames = getJsonValue(msg, "result:callFrames");
- assert(frames != null);
- if (debugger.scriptUrl == null) {
- var name = frames[0]["functionName"];
- if (name == "main") {
- // Extract script url of debugged script.
- debugger.scriptUrl = frames[0]["location"]["url"];
- assert(debugger.scriptUrl != null);
- debugger.libraryId = frames[0]["location"]["libraryId"];
- assert(debugger.libraryId != null);
- }
- }
- if (frames.length < functionNames.length) {
- debugger.error("Error: stack trace not long enough "
- "to match ${functionNames.length} frames");
- return;
- }
- for (int i = 0; i < functionNames.length; i++) {
- var idx = i + frameIndex;
- var name = frames[idx]["functionName"];
- assert(name != null);
- bool isMatch = exactMatch ? name == functionNames[i]
- : name.contains(functionNames[i]);
- if (!isMatch) {
- debugger.error("Error: call frame $idx: "
- "expected function name '${functionNames[i]}' but found '$name'");
- return;
- }
- }
- print("Matched frames: $functionNames");
- }
-}
-
-
-MatchFrame(int frameIndex, String functionName, {exactMatch: false}) {
- return new FrameMatcher(frameIndex, [functionName], exactMatch);
-}
-
-MatchFrames(List<String> functionNames, {exactMatch: false}) {
- return new FrameMatcher(0, functionNames, exactMatch);
-}
-
-
-class LocalsMatcher extends Command {
- Map locals = {};
-
- LocalsMatcher(this.locals) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
-
- List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
- assert(frames != null);
-
- String functionName = frames[0]['functionName'];
- List localsList = frames[0]['locals'];
- Map reportedLocals = {};
- localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
- for (String key in locals.keys) {
- if (reportedLocals[key] == null) {
- debugger.error("Error in $functionName(): no value reported for local "
- "variable $key");
- return;
- }
- String expected = locals[key];
- String actual = reportedLocals[key]['text'];
- if (expected != actual) {
- debugger.error("Error in $functionName(): got '$actual' for local "
- "variable $key, but expected '$expected'");
- return;
- }
- }
- print("Matched locals ${locals.keys}");
- }
-}
-
-
-MatchLocals(Map localValues) {
- return new LocalsMatcher(localValues);
-}
-
-
-// Used to check if local variables are visible.
-class AssertLocalsNotVisibleMatcher extends Command {
- List<String> locals;
- int frame_index;
-
- AssertLocalsNotVisibleMatcher(this.locals, this.frame_index) {
- template = {"id": 0, "command": "getStackTrace", "params": {"isolateId": 0}};
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
-
- List frames = getJsonValue(debugger.currentMessage, "result:callFrames");
- assert(frames != null);
-
- String functionName = frames[frame_index]['functionName'];
- List localsList = frames[frame_index]['locals'];
- Map reportedLocals = {};
- localsList.forEach((local) => reportedLocals[local['name']] = local['value']);
- for (String key in locals) {
- if (reportedLocals[key] != null) {
- debugger.error("Error in $functionName(): local variable $key not "
- "expected in scope (reported value "
- "${reportedLocals[key]['text']})");
- return;
- }
- }
- print("Matched locals $locals");
- }
-}
-
-
-AssertLocalsNotVisible(List<String> locals, [int frame_index = 0]) {
- return new AssertLocalsNotVisibleMatcher(locals, frame_index);
-}
-
-
-class EventMatcher {
- String eventName;
- Map params;
-
- EventMatcher(this.eventName, this.params);
-
- void matchEvent(Debugger debugger) {
- for (Event event in debugger.events) {
- if (event.name == eventName) {
- if (params == null || matchMaps(params, event.params)) {
- // Remove the matched event, so we don't match against it in the future.
- debugger.events.remove(event);
- return;
- }
- }
- }
-
- String msg = params == null ? '' : params.toString();
- debugger.error("Error: could not match event $eventName $msg");
- }
-}
-
-
-ExpectEvent(String eventName, [Map params]) {
- return new EventMatcher(eventName, params);
-}
-
-
-class RunCommand extends Command {
- RunCommand.resume() {
- template = {"id": 0, "command": "resume", "params": {"isolateId": 0}};
- }
- RunCommand.step() {
- template = {"id": 0, "command": "stepOver", "params": {"isolateId": 0}};
- }
- RunCommand.stepInto() {
- template = {"id": 0, "command": "stepInto", "params": {"isolateId": 0}};
- }
- RunCommand.stepOut() {
- template = {"id": 0, "command": "stepOut", "params": {"isolateId": 0}};
- }
- void send(Debugger debugger) {
- debugger.sendMessage(template);
- debugger.isPaused = false;
- }
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- print("Command: ${template['command']}");
- }
-}
-
-
-Resume() => new RunCommand.resume();
-Step() => new RunCommand.step();
-StepInto() => new RunCommand.stepInto();
-StepOut() => new RunCommand.stepOut();
-
-class SetBreakpointCommand extends Command {
- int line;
- String url;
- SetBreakpointCommand(this.line, this.url) {
- template = {"id": 0,
- "command": "setBreakpoint",
- "params": { "isolateId": 0,
- "url": null,
- "line": null }};
- }
-
- void send(Debugger debugger) {
- assert(debugger.scriptUrl != null);
- if (url == null) {
- url = debugger.scriptUrl;
- }
- template["params"]["url"] = url;
- template["params"]["line"] = line;
- debugger.sendMessage(template);
- }
-
- void matchResponse(Debugger debugger) {
- super.matchResponse(debugger);
- print("Set breakpoint at line $line in $url");
- }
-}
-
-SetBreakpoint(int line, {String url}) => new SetBreakpointCommand(line, url);
-
-class Event {
- String name;
- Map params;
-
- Event(Map json) {
- name = json['event'];
- params = json['params'];
- }
-}
-
-
-// A debug script is a list of Command objects.
-class DebugScript {
- List entries;
- DebugScript(List scriptEntries) {
- entries = new List.from(scriptEntries.reversed);
- entries.add(new GetLineTableCmd());
- entries.add(MatchFrame(0, "main"));
- }
- bool get isEmpty => entries.isEmpty;
- bool get isNextEventMatcher => !isEmpty && currentEntry is EventMatcher;
- get currentEntry => entries.last;
- advance() => entries.removeLast();
- add(entry) => entries.add(entry);
-}
-
-
-class Debugger {
- // Debug target process properties.
- Process targetProcess;
- Socket socket;
- JsonBuffer responses = new JsonBuffer();
-
- DebugScript script;
- int seqNr = 0; // Sequence number of next debugger command message.
- Command lastCommand = null; // Most recent command sent to target.
- List<String> errors = new List();
- List<Event> events = new List();
- bool cleanupDone = false;
-
- // Data collected from debug target.
- Map currentMessage = null; // Currently handled message sent by target.
- String scriptUrl = null;
- int libraryId = null;
- Map<int,int> tokenToLine = null;
- bool shutdownEventSeen = false;
- int isolateId = 0;
- bool isPaused = false;
-
- Debugger(this.targetProcess, this.script) {
- var stdoutStringStream = targetProcess.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stdoutStringStream.listen((line) {
- print("TARG: $line");
- if (line.startsWith("Debugger listening")) {
- RegExp portExpr = new RegExp(r"\d+");
- var port = portExpr.stringMatch(line);
- print("Debug target found listening at port '$port'");
- openConnection(int.parse(port));
- }
- });
-
- var stderrStringStream = targetProcess.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stderrStringStream.listen((line) {
- print("TARG: $line");
- });
- }
-
- // Handle debugger events, updating the debugger state.
- void handleEvent(Map<String,dynamic> msg) {
- events.add(new Event(msg));
-
- if (msg["event"] == "isolate") {
- if (msg["params"]["reason"] == "created") {
- isolateId = msg["params"]["id"];
- assert(isolateId != null);
- print("Debuggee isolate id $isolateId created.");
- } else if (msg["params"]["reason"] == "shutdown") {
- print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
- shutdownEventSeen = true;
- if (!script.isEmpty) {
- error("Error: premature isolate shutdown event seen.");
- error("Next expected event: ${script.currentEntry}");
- }
- }
- } else if (msg["event"] == "breakpointResolved") {
- var bpId = msg["params"]["breakpointId"];
- assert(bpId != null);
- var isolateId = msg["params"]["isolateId"];
- assert(isolateId != null);
- var location = msg["params"]["location"];
- assert(location != null);
- print("Isolate $isolateId: breakpoint $bpId resolved"
- " at location $location");
- // We may want to maintain a table of breakpoints in the future.
- } else if (msg["event"] == "paused") {
- isPaused = true;
- } else {
- error("Error: unknown debugger event received");
- }
- }
-
- // Handle one JSON message object and match it to the
- // expected events and responses in the debugging script.
- void handleMessage(Map<String,dynamic> receivedMsg) {
- currentMessage = receivedMsg;
- if (receivedMsg["event"] != null) {
- handleEvent(receivedMsg);
- if (errorsDetected) {
- error("Error while handling debugger event");
- error("Event received from debug target: $receivedMsg");
- }
- } else if (receivedMsg["id"] != null) {
- // This is a response to the last command we sent.
- assert(lastCommand != null);
- lastCommand.matchResponse(this);
- lastCommand = null;
- if (errorsDetected) {
- error("Error while matching response to debugger command");
- error("Response received from debug target: $receivedMsg");
- }
- }
- }
-
- // Send next debugger command in the script, if a response
- // from the last command has been received and processed.
- void sendNextCommand() {
- while (script.isNextEventMatcher) {
- EventMatcher matcher = script.currentEntry;
- script.advance();
- matcher.matchEvent(this);
- }
-
- if (lastCommand == null) {
- if (script.currentEntry is Command) {
- script.currentEntry.send(this);
- lastCommand = script.currentEntry;
- seqNr++;
- script.advance();
- }
- }
- }
-
- // Handle data received over the wire from the debug target
- // process. Split input from JSON wire format into individual
- // message objects (maps).
- void handleMessages() {
- var msg = responses.getNextMessage();
- while (msg != null) {
- if (verboseWire) print("RECV: $msg");
- if (responses.haveGarbage()) {
- error("Error: leftover text after message: '${responses.buffer}'");
- error("Previous message may be malformed, was: '$msg'");
- cleanup();
- return;
- }
- var msgObj = JSON.decode(msg);
- handleMessage(msgObj);
- if (errorsDetected) {
- error("Error while handling script entry");
- error("Message received from debug target: $msg");
- cleanup();
- return;
- }
- if (shutdownEventSeen) {
- cleanup();
- return;
- }
- if (isPaused) sendNextCommand();
- msg = responses.getNextMessage();
- }
- }
-
- // Send a debugger command to the target VM.
- void sendMessage(Map<String,dynamic> msg) {
- if (msg["id"] != null) {
- msg["id"] = seqNr;
- }
- if (msg["params"] != null && msg["params"]["isolateId"] != null) {
- msg["params"]["isolateId"] = isolateId;
- }
- String jsonMsg = JSON.encode(msg);
- if (verboseWire) print("SEND: $jsonMsg");
- socket.write(jsonMsg);
- }
-
- bool get errorsDetected => errors.length > 0;
-
- // Record error message.
- void error(String s) {
- errors.add(s);
- }
-
- void openConnection(int portNumber) {
- Socket.connect("127.0.0.1", portNumber).then((s) {
- s.setOption(SocketOption.TCP_NODELAY, true);
- this.socket = s;
- var stringStream = socket.transform(UTF8.decoder);
- stringStream.listen((str) {
- try {
- responses.append(str);
- handleMessages();
- } catch(e, trace) {
- print("Unexpected exception:\n$e\n$trace");
- cleanup();
- }
- },
- onDone: () {
- print("Connection closed by debug target");
- cleanup();
- },
- onError: (e, trace) {
- print("Error '$e' detected in input stream from debug target");
- if (trace != null) print("StackTrace: $trace");
- cleanup();
- });
- },
- onError: (e, trace) {
- String msg = "Error while connecting to debugee: $e";
- if (trace != null) msg += "\nStackTrace: $trace";
- error(msg);
- cleanup();
- });
- }
-
- void cleanup() {
- if (cleanupDone) return;
- if (socket != null) {
- socket.close().catchError((error) {
- // Print this directly in addition to adding it to the
- // error message queue, in case the error message queue
- // gets printed before this error handler is called.
- print("Error occurred while closing socket: $error");
- error("Error while closing socket: $error");
- });
- }
- var targetPid = targetProcess.pid;
- if (errorsDetected || !shutdownEventSeen) {
- print("Sending kill signal to process $targetPid...");
- targetProcess.kill();
- }
- // If the process was already dead, exitCode is
- // available and we call exit() in the next event loop cycle.
- // Otherwise this will wait for the process to exit.
- targetProcess.exitCode.then((exitCode) {
- print("process $targetPid terminated with exit code $exitCode.");
- if (exitCode != 0) {
- error("Error: target process died with exit code $exitCode");
- }
- if (errorsDetected) {
- print("\n===== Errors detected: =====");
- for (int i = 0; i < errors.length; i++) print(errors[i]);
- print("============================\n");
- }
- exit(errors.length);
- });
- cleanupDone = true;
- }
-}
-
-
-bool RunScript(List script, List<String> arguments) {
- if (arguments.contains("--debuggee")) {
- return false;
- }
- verboseWire = arguments.contains("--wire");
-
- // Port number 0 means debug target picks a free port dynamically.
- var targetOpts = [ "--debug:0" ];
- if (arguments.contains("--verbose")) {
- targetOpts.add("--verbose_debug");
- }
- targetOpts.add(Platform.script.toFilePath());
- targetOpts.add("--debuggee");
- print('args: ${targetOpts.join(" ")}');
-
- Process.start(Platform.executable, targetOpts).then((Process process) {
- print("Debug target process started, pid ${process.pid}.");
- process.stdin.close();
- var debugger = new Debugger(process, new DebugScript(script));
- });
- return true;
-}
diff --git a/tests/standalone/debugger/deferred_code_lib.dart b/tests/standalone/debugger/deferred_code_lib.dart
deleted file mode 100644
index 4506217..0000000
--- a/tests/standalone/debugger/deferred_code_lib.dart
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library lazyCode;
-
-void stopTheBuck() {
- // Line number of print call must match breakpoint request
- // in deferred_code_test.dart.
- print("The debugger stops here.");
-}
diff --git a/tests/standalone/debugger/deferred_code_test.dart b/tests/standalone/debugger/deferred_code_test.dart
deleted file mode 100644
index c4578ab..0000000
--- a/tests/standalone/debugger/deferred_code_test.dart
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Test to verify that a breakpoint can be set in code that is not yet
-// loaded, i.e. in a deferred library.
-//
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-import "deferred_code_lib.dart" deferred as D;
-
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- var loaded = false;
- print("Hello from debuggee");
- D.loadLibrary().then((_) {
- loaded = true;
- print("Done loading deferred library");
- D.stopTheBuck();
- });
- print("main terminates");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(22), // Breakpoint just before call to loadLibrary().
- Resume(),
- // Set BP in deferred library code before the loadLibrary() call is executed.
- MatchFrame(0, "main"),
- MatchLine(22),
- MatchLocals({"loaded": "false"}),
- SetBreakpoint(10, url: "deferred_code_lib.dart"),
- // Regression test: we used to have a bug that hung the debugger when
- // processing latent brakepoints for urls that have no match.
- // The BP below will not match any loaded file.
- SetBreakpoint(10, url: "non_existing_file.dart"),
- Resume(),
- MatchFrame(0, "stopTheBuck"), // Expect to be stopped in deferred library code.
- // MatchLine(10), // Line matching only works for the main script.
- Resume(),
-];
diff --git a/tests/standalone/debugger/local_function_test.dart b/tests/standalone/debugger/local_function_test.dart
deleted file mode 100644
index 98df8fe..0000000
--- a/tests/standalone/debugger/local_function_test.dart
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-// Check that if a breakpoint is requested on the line containing the
-// one-liner with a local function below, the breakpoint gets set in
-// the outer function.
-foo(x) => (n) => x * n; // Breakpoint 1 on this line.
-
-// Check that if a breakpoint is requested on the line "return n*x"
-// below, the breakpoint is set in the local function (closure).
-bar(x) {
- return (n) {
- return n * x; // Breakpoint 2 on this line.
- };
-}
-
-// Check that setting a breakpoint works in the case where the
-// class has not been parsed yet.
-// No reference to class C must appear in main(), so that the class is not
-// yet parsed when the breakpoint in the closure nested in the constructor
-// is set.
-class C {
- var closure;
- C() {
- closure = () {
- var z = 10; // Breakpoint 3 on this line.
- z = z * 2;
- return z;
- };
- }
-}
-
-checkBpInLazilyParsedClass() {
- var c = new C();
- c.closure(); // Expected to hit breakpoint.
-}
-
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- var f = foo(10); // Hits breakpoint.
- print(f(5));
- var b = bar(10);
- print(b(10)); // Hits breakpoint.
- checkBpInLazilyParsedClass();
-}
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(17), // Breakpoint 1 in function foo.
- SetBreakpoint(23), // Breakpoint 2 in local function inside bar.
- SetBreakpoint(36), // Breakpoint 3 in local function inside constructor C.
- Resume(),
- MatchFrames(["foo", "main"]),
- Resume(),
- MatchFrames(["<anonymous closure>", "main"]),
- Resume(),
- MatchFrames(["C.<anonymous closure>", "checkBpInLazilyParsedClass"]),
- Resume(),
-];
diff --git a/tests/standalone/debugger/local_variables_test.dart b/tests/standalone/debugger/local_variables_test.dart
deleted file mode 100644
index b7871d4..0000000
--- a/tests/standalone/debugger/local_variables_test.dart
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-foo() {
- var y; // Breakpoint
- return 123;
-}
-
-test() {
- if (true) {
- var temp = 777;
- }
- if (true) {
- var a = foo(); // Breakpoint
- if (true) {
- var s = 456;
- print(s);
- }
- }
-}
-
-test_no_init() {
- if (true) {
- var temp = 777;
- }
- if (true) {
- var a; // Breakpoint
- if (true) {
- var s = 456;
- print(s);
- }
- }
-}
-
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- test();
- test_no_init();
- print("Hello again");
-}
-
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- Step(),
- MatchFrame(0, "main"), // Should still be in "main".
- SetBreakpoint(15), // Set breakpoint in function foo.
- SetBreakpoint(24), // Set breakpoint in function test.
- SetBreakpoint(37), // Set breakpoint in function test_no_init.
- Resume(),
- MatchFrames(["test", "main"]),
- AssertLocalsNotVisible(["a"]), // Here, a is not in scope yet.
- Resume(),
- MatchFrames(["foo", "test", "main"]),
- AssertLocalsNotVisible(["a"], 1), // In the caller, a is not in scope.
- Step(),
- MatchLocals({"y": "null"}), // Expect y initialized to null.
- Resume(),
- MatchFrames(["test_no_init", "main"]),
- AssertLocalsNotVisible(["a"]), // a is not in scope.
- Step(),
- MatchLocals({"a": "null"}),
- Resume()
-];
diff --git a/tests/standalone/debugger/mixin_closure_debugger_test.dart b/tests/standalone/debugger/mixin_closure_debugger_test.dart
deleted file mode 100644
index 5e6fd5e..0000000
--- a/tests/standalone/debugger/mixin_closure_debugger_test.dart
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-// This test checks that a breakpoint can be set and is hit in a closure
-// inside a mixin function. Regression test for issue 15325.
-
-import "debug_lib.dart";
-
-class S { }
-
-class M {
- m() {
- var sum = 0;
- [1,2,3].forEach((e) {
- sum += e; // Breakpoint here.
- });
- return sum;
- }
-}
-
-class A = S with M;
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- var a = new A();
- print(a.m());
-}
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(23), // Set breakpoint inside the forEach closure.
- Resume(),
- MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
- exactMatch: false), // First iteration.
- MatchLocals({"e": "1"}),
- Resume(),
- MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
- exactMatch: false), // Second iteration.
- MatchLocals({"e": "2"}),
- Resume(),
- MatchFrames(["S&M.<anonymous closure>", "forEach", "S&M.m"],
- exactMatch: false), // Third iteration.
- MatchLocals({"e": "3"}),
- Resume(),
-];
diff --git a/tests/standalone/debugger/nosuchmethod_debugger_test.dart b/tests/standalone/debugger/nosuchmethod_debugger_test.dart
deleted file mode 100644
index 10b6855..0000000
--- a/tests/standalone/debugger/nosuchmethod_debugger_test.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs this dart script as
-// a debug target.
-// Run this test with option --wire to see the json messages sent
-// between the processes.
-// Run this test with option --verbose to see the stdout and stderr output
-// of the debug target process.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
- print("Hello from debuggee");
- var a = new A();
- for (var i = 0; i < 2; ++i) {
- a.foo(i);
- }
-}
-
-class A {
- noSuchMethod(m) {
- print(m.positionalArguments[0]);
- }
-}
-
-// Expected debugger events and commands.
-var testScript = [
- MatchFrame(0, "main"), // Top frame in trace is function "main".
- SetBreakpoint(19), // Set breakpoint at a.foo(i).
- Resume(),
- MatchFrame(0, "main"), // Should be at closure call.
- MatchLocals({"i": "0"}),
- StepInto(),
- StepInto(),
- MatchFrames(["A.noSuchMethod", "main"]),
- StepOut(),
- MatchFrame(0, "main"), // Back in main.
- Resume(),
- MatchFrame(0, "main"), // Still in main back at a.foo(i).
- MatchLocals({"i": "1"}),
- StepInto(),
- StepInto(),
- MatchFrames(["A.noSuchMethod", "main"]), // Second invocation.
- Resume()
-];
diff --git a/tests/standalone/debugger/step_inout_test.dart b/tests/standalone/debugger/step_inout_test.dart
deleted file mode 100644
index 421c212..0000000
--- a/tests/standalone/debugger/step_inout_test.dart
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
-
- foo('foo1');
- foo('foo2');
- foo('foo3');
-}
-
-void foo(String str) {
- print(str);
-}
-
-/**
- * Set a breakpoint, resume to that breakpoint, step into a method, step out,
- * step over the next line, and resume execution.
- */
-var testScript = [
- MatchFrames(["main"]),
- SetBreakpoint(10),
- Resume(),
- MatchFrames(["main"]),
- StepInto(),
- MatchFrames(["foo", "main"]),
- StepOut(),
- MatchFrames(["main"]),
- Step(),
- MatchFrames(["main"]),
- Resume(),
-];
diff --git a/tests/standalone/debugger/stepping_test.dart b/tests/standalone/debugger/stepping_test.dart
deleted file mode 100644
index d8f37d2..0000000
--- a/tests/standalone/debugger/stepping_test.dart
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
-
- bar();
-}
-
-void bar() {
- print('foo1');
- print('foo2');
- print('foo3');
-}
-
-/**
- * Set a breakpoint, resume to that breakpoint, step once, and verify that the
- * step worked.
- */
-var testScript = [
- MatchFrames(["main"]),
- SetBreakpoint(15),
- Resume(),
- MatchFrames(["bar"]),
- Step(),
- MatchFrames(["bar"]),
- Resume(),
-];
diff --git a/tests/standalone/debugger/tostring_throws_test.dart b/tests/standalone/debugger/tostring_throws_test.dart
deleted file mode 100644
index 7214bb2..0000000
--- a/tests/standalone/debugger/tostring_throws_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "debug_lib.dart";
-
-main(List<String> arguments) {
- if (RunScript(testScript, arguments)) return;
-
- Foo foo = new Foo();
-
- print("Hello from debuggee");
-}
-
-class Foo {
- String toString() {
- throw 'I always throw';
- }
-}
-
-// Make sure Foo.toString() does not get called.
-var testScript = [
- MatchFrame(0, "main"),
- SetBreakpoint(12),
- Resume(),
- MatchFrame(0, "main"),
- MatchLocals({"foo": "object of type Foo"}),
- Resume(),
-];
diff --git a/tests/standalone/precompilation_dart2js_test.dart b/tests/standalone/precompilation_dart2js_test.dart
index c961a5e..52957d7 100644
--- a/tests/standalone/precompilation_dart2js_test.dart
+++ b/tests/standalone/precompilation_dart2js_test.dart
@@ -87,7 +87,7 @@
var ld_library_path = new String.fromEnvironment("LD_LIBRARY_PATH");
ld_library_path = "${ld_library_path}:${tmp.path}";
- exec = "${dart_executable}";
+ exec = "${dart_executable}_precompiled";
args = ["--run-precompiled-snapshot", "ignored_script", "--version"];
print("LD_LIBRARY_PATH=$ld_library_path $exec ${args.join(' ')}");
result = Process.runSync(exec, args,
diff --git a/tests/standalone/precompilation_test.dart b/tests/standalone/precompilation_test.dart
index 047ac0d..751682e 100644
--- a/tests/standalone/precompilation_test.dart
+++ b/tests/standalone/precompilation_test.dart
@@ -86,7 +86,7 @@
ld_library_path = "${ld_library_path}:${tmp.path}";
result = Process.runSync(
- "${dart_executable}",
+ "${dart_executable}_precompiled",
["--run-precompiled-snapshot", "ignored_script", "--hello"],
workingDirectory: tmp.path,
environment: {"LD_LIBRARY_PATH": ld_library_path});
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index b136d43..5891105 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -50,8 +50,6 @@
typed_data_isolate_test: SkipByDesign # This test uses dart:io
io/*: SkipByDesign # Don't run tests using dart:io in the browser
package/*: Skip # Do not run those in Dartium.
-debugger/*: SkipByDesign # Do not run standalone debugger tests in browser.
-coverage_test: Skip
full_coverage_test: Skip
http_launch_test: Skip
vmservice/*: SkipByDesign # Do not run standalone vm service tests in browser.
@@ -91,7 +89,6 @@
package/package_isolate_test: Skip # spawnUri does not work in dart2js. See issue 3051
package/package_test: Fail, OK # dart2js does not support 'package:foo.dart' imports
package/package1_test: Fail, OK # dart2js does not support 'package:foo.dart' imports
-debugger/*: Skip # Do not run standalone vm debugger tests with dart2js.
full_coverage_test: Skip
left_shift_bit_and_op_test: Skip # Integers exceed dart2js precision.
pow_test: Skip # Precision > 53 bits.
@@ -110,16 +107,19 @@
precompilation_dart2js_test: Skip # Standalone only test.
noopt_test: Skip # Standalone only test.
-[ $runtime == vm && $arch == ia32]
+[ $runtime == vm && $mode == debug ]
+precompilation_dart2js_test: Pass, Slow
+
+[ $runtime == vm && $arch == ia32 ]
precompilation_test: Skip # Not expected to pass on ia32.
precompilation_dart2js_test: Skip # Not expected to pass on ia32.
noopt_test: Skip # Not expected to pass on ia32.
-[ $runtime == vm && $arch == arm]
+[ $runtime == vm && $arch == arm ]
precompilation_test: Skip # Issue 24427
precompilation_dart2js_test: Skip # Issue 24427
-[ $runtime == vm && $arch == mips]
+[ $runtime == vm && $arch == mips ]
precompilation_dart2js_test: SkipSlow
[ $compiler == dart2js && $jscl ]
@@ -136,7 +136,7 @@
[ $compiler == dart2js && $browser ]
*: Skip
-[ $arch == simarm || $arch == simarmv5te || $arch == simmips]
+[ $arch == simarm || $arch == simarmv5te || $arch == simmips ]
out_of_memory_test: Skip # passes on Mac, crashes on Linux
oom_error_stacktrace_test: Skip # Fails on Linux
@@ -200,6 +200,7 @@
io/skipping_dart2js_compilations_test: Fail # Issue 19551.
verbose_gc_to_bmu_test: Skip
io/platform_resolved_executable_test/06: RuntimeError # Issue 23641
+io/process_sync_test: Pass, Timeout # Issue 24596
[ $arch != ia32 && $arch != x64 && $arch != simarm && $arch != simarmv5te && $mode == debug ]
verified_mem_test: Skip # Not yet implemented.
diff --git a/tests/standalone/typed_array_int64_uint64_test.dart b/tests/standalone/typed_array_int64_uint64_test.dart
index 3decb92..f62ab53 100644
--- a/tests/standalone/typed_array_int64_uint64_test.dart
+++ b/tests/standalone/typed_array_int64_uint64_test.dart
@@ -7,12 +7,19 @@
// Library tag to be able to run in html test framework.
library TypedArray;
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
+import 'dart:async';
import 'dart:isolate';
import 'dart:typed_data';
-void main() {
- int64_receiver();
- uint64_receiver();
+main() {
+ test(int64_receiver);
+ test(uint64_receiver);
+}
+
+test(f) {
+ asyncStart();
+ return f().whenComplete(asyncEnd);
}
// Int64 array.
@@ -24,15 +31,17 @@
}
Int64List int64 = initInt64();
-void int64_receiver() {
+int64_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(int64_sender, [int64.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(int64.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(int64[i], a[i]);
}
print("int64_receiver");
+ asyncEnd();
});
}
@@ -57,15 +66,17 @@
}
Uint64List uint64 = initUint64();
-void uint64_receiver() {
+uint64_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(uint64_sender, [uint64.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(uint64.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(uint64[i], a[i]);
}
print("uint64_receiver");
+ asyncEnd();
});
}
diff --git a/tests/standalone/typed_array_test.dart b/tests/standalone/typed_array_test.dart
index 9643e13e..0c4c2b1 100644
--- a/tests/standalone/typed_array_test.dart
+++ b/tests/standalone/typed_array_test.dart
@@ -8,19 +8,25 @@
// Library tag to be able to run in html test framework.
library TypedArray;
import "package:expect/expect.dart";
+import 'package:async_helper/async_helper.dart';
import 'dart:isolate';
import 'dart:typed_data';
void main() {
- int8_receiver();
- uint8_receiver();
- int16_receiver();
- uint16_receiver();
- int32_receiver();
- uint32_receiver();
+ test(int8_receiver);
+ test(uint8_receiver);
+ test(int16_receiver);
+ test(uint16_receiver);
+ test(int32_receiver);
+ test(uint32_receiver);
// int64 and uint64 in separate test.
- float32_receiver();
- float64_receiver();
+ test(float32_receiver);
+ test(float64_receiver);
+}
+
+test(f) {
+ asyncStart();
+ return f().whenComplete(asyncEnd);
}
// Int8 array.
@@ -32,15 +38,17 @@
}
Int8List int8 = initInt8();
-void int8_receiver() {
+int8_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(int8_sender, [int8.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(int8.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(int8[i], a[i]);
}
print("int8_receiver");
+ asyncEnd();
});
}
@@ -65,15 +73,17 @@
}
Uint8List uint8 = initUint8();
-void uint8_receiver() {
+uint8_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(uint8_sender, [uint8.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(uint8.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(uint8[i], a[i]);
}
print("uint8_receiver");
+ asyncEnd();
});
}
@@ -98,15 +108,17 @@
}
Int16List int16 = initInt16();
-void int16_receiver() {
+int16_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(int16_sender, [int16.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(int16.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(int16[i], a[i]);
}
print("int16_receiver");
+ asyncEnd();
});
}
@@ -131,15 +143,17 @@
}
Uint16List uint16 = initUint16();
-void uint16_receiver() {
+uint16_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(uint16_sender, [uint16.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(uint16.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(uint16[i], a[i]);
}
print("uint16_receiver");
+ asyncEnd();
});
}
@@ -164,15 +178,17 @@
}
Int32List int32 = initInt32();
-void int32_receiver() {
+int32_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(int32_sender, [int32.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(int32.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(int32[i], a[i]);
}
print("int32_receiver");
+ asyncEnd();
});
}
@@ -197,15 +213,17 @@
}
Uint32List uint32 = initUint32();
-void uint32_receiver() {
+uint32_receiver() {
var response = new ReceivePort();
var remote = Isolate.spawn(uint32_sender, [uint32.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(uint32.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(uint32[i], a[i]);
}
print("uint32_receiver");
+ asyncEnd();
});
}
@@ -230,16 +248,18 @@
}
Float32List float32 = initFloat32();
-void float32_receiver() {
+float32_receiver() {
var response = new ReceivePort();
var remote =
Isolate.spawn(float32_sender, [float32.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(float32.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(float32[i], a[i]);
}
print("float32_receiver");
+ asyncEnd();
});
}
@@ -264,16 +284,18 @@
}
Float64List float64 = initFloat64();
-void float64_receiver() {
+float64_receiver() {
var response = new ReceivePort();
var remote =
Isolate.spawn(float64_sender, [float64.length, response.sendPort]);
- response.first.then((a) {
+ asyncStart();
+ return response.first.then((a) {
Expect.equals(float64.length, a.length);
for (int i = 0; i < a.length; i++) {
Expect.equals(float64[i], a[i]);
}
print("float64_receiver");
+ asyncEnd();
});
}
diff --git a/tools/FAKE_COMMITS b/tools/FAKE_COMMITS
index 59a3d33..709ba90 100644
--- a/tools/FAKE_COMMITS
+++ b/tools/FAKE_COMMITS
@@ -14,3 +14,4 @@
Trigger bots on github pull
Trigger bots
Purple is the new green.
+googlecode back up
diff --git a/tools/VERSION b/tools/VERSION
index c50dfe1..1998c0e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 14
PATCH 0
-PRERELEASE 1
+PRERELEASE 2
PRERELEASE_PATCH 0
diff --git a/tools/coverage.dart b/tools/coverage.dart
deleted file mode 100644
index b5cc618..0000000
--- a/tools/coverage.dart
+++ /dev/null
@@ -1,545 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// This test forks a second vm process that runs a dart script as
-// a debug target, single stepping through the entire program, and
-// recording each breakpoint. At the end, a coverage map of the source
-// is printed.
-//
-// Usage: dart coverage.dart [--wire] [--verbose] target_script.dart
-//
-// --wire see json messages sent between the processes.
-// --verbose see the stdout and stderr output of the debug
-// target process.
-
-import "dart:convert";
-import "dart:io";
-
-
-// Whether or not to print debug target process on the console.
-var showDebuggeeOutput = false;
-
-// Whether or not to print the debugger wire messages on the console.
-var verboseWire = false;
-
-var debugger = null;
-
-class Program {
- static int numBps = 0;
-
- // Maps source code url to source.
- static var sources = new Map<String, Source>();
-
- // Takes a JSON Debugger response and increments the count for
- // the source position.
- static void recordBp(Map<String,dynamic> msg) {
- // Progress indicator.
- if (++numBps % 1000 == 0) print(numBps);
- var location = msg["params"]["location"];
- if (location == null) return;
- String url = location["url"];
- assert(url != null);
- int libId = location["libraryId"];
- assert(libId != null);
- int tokenPos = location["tokenOffset"];;
- Source s = sources[url];
- if (s == null) {
- debugger.getLineNumberTable(url, libId);
- s = new Source(url);
- sources[url] = s;
- }
- s.recordBp(tokenPos);
- }
-
- // Prints the annotated source code.
- static void printCoverage() {
- print("Coverage info collected from $numBps breakpoints:");
- for(Source s in sources.values) s.printCoverage();
- }
-}
-
-
-class Source {
- final String url;
-
- // Maps token position to breakpoint count.
- final tokenCounts = new Map<int,int>();
-
- // Maps token position to line number.
- final tokenPosToLine = new Map<int,int>();
-
- Source(this.url);
-
- void recordBp(int tokenPos) {
- var count = tokenCounts[tokenPos];
- tokenCounts[tokenPos] = count == null ? 1 : count + 1;
- }
-
- void SetLineInfo(List lineInfoTable) {
- // Each line is encoded as an array with first element being the line
- // number, followed by pairs of (tokenPosition, columnNumber).
- lineInfoTable.forEach((List<int> line) {
- int lineNumber = line[0];
- for (int t = 1; t < line.length; t += 2) {
- assert(tokenPosToLine[line[t]] == null);
- tokenPosToLine[line[t]] = lineNumber;
- }
- });
- }
-
- // Print out the annotated source code. For each line that has seen
- // a breakpoint, print out the maximum breakpoint count for all
- // tokens in the line.
- void printCoverage() {
- var lineCounts = new Map<int,int>(); // BP counts for each line.
- print(url);
- tokenCounts.forEach((tp, bpCount) {
- int lineNumber = tokenPosToLine[tp];
- var lineCount = lineCounts[lineNumber];
- // Remember maximum breakpoint count of all tokens in this line.
- if (lineCount == null || lineCount < bpCount) {
- lineCounts[lineNumber] = bpCount;
- }
- });
-
- String srcPath = Uri.parse(url).toFilePath();
- List lines = new File(srcPath).readAsLinesSync();
- for (int line = 1; line <= lines.length; line++) {
- String prefix = " ";
- if (lineCounts.containsKey(line)) {
- prefix = lineCounts[line].toString();
- StringBuffer b = new StringBuffer();
- for (int i = prefix.length; i < 6; i++) b.write(" ");
- b.write(prefix);
- prefix = b.toString();
- }
- print("${prefix}|${lines[line-1]}");
- }
- }
-}
-
-
-class StepCmd {
- Map msg;
- StepCmd(int isolateId) {
- msg = {"id": 0, "command": "stepInto", "params": {"isolateId": isolateId}};
- }
- void handleResponse(Map response) {}
-}
-
-
-class GetLineTableCmd {
- Map msg;
- GetLineTableCmd(int isolateId, int libraryId, String url) {
- msg = { "id": 0,
- "command": "getLineNumberTable",
- "params": { "isolateId" : isolateId,
- "libraryId": libraryId,
- "url": url } };
- }
-
- void handleResponse(Map response) {
- var url = msg["params"]["url"];
- Source s = Program.sources[url];
- assert(s != null);
- s.SetLineInfo(response["result"]["lines"]);
- }
-}
-
-
-class GetLibrariesCmd {
- Map msg;
- GetLibrariesCmd(int isolateId) {
- msg = { "id": 0,
- "command": "getLibraries",
- "params": { "isolateId" : isolateId } };
- }
-
- void handleResponse(Map response) {
- List libs = response["result"]["libraries"];
- for (var lib in libs) {
- String url = lib["url"];
- int libraryId = lib["id"];
- bool enable = !url.startsWith("dart:") && !url.startsWith("package:");
- if (enable) {
- print("Enable stepping for '$url'");
- debugger.enableDebugging(libraryId, true);
- }
- }
- }
-}
-
-
-class SetLibraryPropertiesCmd {
- Map msg;
- SetLibraryPropertiesCmd(int isolateId, int libraryId, bool enableDebugging) {
- // Note that in the debugger protocol, boolean values true and false
- // must be sent as string literals.
- msg = { "id": 0,
- "command": "setLibraryProperties",
- "params": { "isolateId" : isolateId,
- "libraryId": libraryId,
- "debuggingEnabled": "$enableDebugging" } };
- }
-
- void handleResponse(Map response) {
- // Nothing to do.
- }
-}
-
-
-class Debugger {
- // Debug target process properties.
- Process targetProcess;
- Socket socket;
- bool cleanupDone = false;
- JsonBuffer responses = new JsonBuffer();
- List<String> errors = new List();
-
- // Data collected from debug target.
- Map currentMessage = null; // Currently handled message sent by target.
- var outstandingCommand = null;
- var queuedCommands = new List();
- String scriptUrl = null;
- bool shutdownEventSeen = false;
- int isolateId = 0;
- int libraryId = null;
-
- int nextMessageId = 0;
- bool isPaused = false;
- bool pendingAck = false;
-
- Debugger(this.targetProcess) {
- var stdoutStringStream = targetProcess.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stdoutStringStream.listen((line) {
- if (showDebuggeeOutput) {
- print("TARG: $line");
- }
- if (line.startsWith("Debugger listening")) {
- RegExp portExpr = new RegExp(r"\d+");
- var port = portExpr.stringMatch(line);
- var pid = targetProcess.pid;
- print("Coverage target process (pid $pid) found "
- "listening on port $port.");
- openConnection(int.parse(port));
- }
- });
-
- var stderrStringStream = targetProcess.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter());
- stderrStringStream.listen((line) {
- if (showDebuggeeOutput) {
- print("TARG: $line");
- }
- });
- }
-
- // Handle debugger events, updating the debugger state.
- void handleEvent(Map<String,dynamic> msg) {
- if (msg["event"] == "isolate") {
- if (msg["params"]["reason"] == "created") {
- isolateId = msg["params"]["id"];
- assert(isolateId != null);
- print("Debuggee isolate id $isolateId created.");
- } else if (msg["params"]["reason"] == "shutdown") {
- print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
- shutdownEventSeen = true;
- }
- } else if (msg["event"] == "breakpointResolved") {
- var bpId = msg["params"]["breakpointId"];
- assert(bpId != null);
- var isolateId = msg["params"]["isolateId"];
- assert(isolateId != null);
- var location = msg["params"]["location"];
- assert(location != null);
- print("Isolate $isolateId: breakpoint $bpId resolved"
- " at location $location");
- // We may want to maintain a table of breakpoints in the future.
- } else if (msg["event"] == "paused") {
- isPaused = true;
- if (libraryId == null) {
- libraryId = msg["params"]["location"]["libraryId"];
- assert(libraryId != null);
- // This is the first paused event we got. Get all libraries from
- // the debugger so we can turn on debugging events for them.
- getLibraries();
- }
- if (msg["params"]["reason"] == "breakpoint") {
- Program.recordBp(msg);
- }
- } else {
- error("Error: unknown debugger event received");
- }
- }
-
- // Handle one JSON message object.
- void handleMessage(Map<String,dynamic> receivedMsg) {
- currentMessage = receivedMsg;
- if (receivedMsg["event"] != null) {
- handleEvent(receivedMsg);
- if (errorsDetected) {
- error("Error while handling event message");
- error("Event received from coverage target: $receivedMsg");
- }
- } else if (receivedMsg["id"] != null) {
- // This is a response to the last command we sent.
- int id = receivedMsg["id"];
- assert(outstandingCommand != null);
- assert(outstandingCommand.msg["id"] == id);
- outstandingCommand.handleResponse(receivedMsg);
- outstandingCommand = null;
- } else {
- error("Unexpected message from target");
- }
- }
-
- // Handle data received over the wire from the coverage target
- // process. Split input from JSON wire format into individual
- // message objects (maps).
- void handleMessages() {
- var msg = responses.getNextMessage();
- while (msg != null) {
- if (verboseWire) print("RECV: $msg");
- if (responses.haveGarbage()) {
- error("Error: leftover text after message: '${responses.buffer}'");
- error("Previous message may be malformed, was: '$msg'");
- cleanup();
- return;
- }
- var msgObj = JSON.decode(msg);
- handleMessage(msgObj);
- if (errorsDetected) {
- error("Error while handling message from coverage target");
- error("Message received from coverage target: $msg");
- cleanup();
- return;
- }
- if (shutdownEventSeen) {
- if (outstandingCommand != null) {
- error("Error: outstanding command when shutdown received");
- }
- cleanup();
- return;
- }
- if (isPaused && (outstandingCommand == null)) {
- var cmd = queuedCommands.length > 0 ? queuedCommands.removeAt(0) : null;
- if (cmd == null) {
- cmd = new StepCmd(isolateId);
- isPaused = false;
- }
- sendMessage(cmd.msg);
- outstandingCommand = cmd;
- }
- msg = responses.getNextMessage();
- }
- }
-
- // Send a debugger command to the target VM.
- void sendMessage(Map<String,dynamic> msg) {
- assert(msg["id"] != null);
- msg["id"] = nextMessageId++;
- String jsonMsg = JSON.encode(msg);
- if (verboseWire) print("SEND: $jsonMsg");
- socket.write(jsonMsg);
- }
-
- void getLineNumberTable(String url, int libId) {
- queuedCommands.add(new GetLineTableCmd(isolateId, libId, url));
- }
-
- void getLibraries() {
- queuedCommands.add(new GetLibrariesCmd(isolateId));
- }
-
- void enableDebugging(libraryId, enable) {
- queuedCommands.add(new SetLibraryPropertiesCmd(isolateId, libraryId, enable));
- }
-
- bool get errorsDetected => errors.length > 0;
-
- // Record error message.
- void error(String s) {
- errors.add(s);
- }
-
- void openConnection(int portNumber) {
- Socket.connect("127.0.0.1", portNumber).then((s) {
- socket = s;
- socket.setOption(SocketOption.TCP_NODELAY, true);
- var stringStream = socket.transform(UTF8.decoder);
- stringStream.listen(
- (str) {
- try {
- responses.append(str);
- handleMessages();
- } catch(e, trace) {
- print("Unexpected exception:\n$e\n$trace");
- cleanup();
- }
- },
- onDone: () {
- print("Connection closed by coverage target");
- cleanup();
- },
- onError: (e) {
- print("Error '$e' detected in input stream from coverage target");
- cleanup();
- });
- },
- onError: (e, trace) {
- String msg = "Error while connecting to coverage target: $e";
- if (trace != null) msg += "\nStackTrace: $trace";
- error(msg);
- cleanup();
- });
- }
-
- void cleanup() {
- if (cleanupDone) return;
- if (socket != null) {
- socket.close().catchError((error) {
- // Print this directly in addition to adding it to the
- // error message queue, in case the error message queue
- // gets printed before this error handler is called.
- print("Error occurred while closing socket: $error");
- error("Error while closing socket: $error");
- });
- }
- var targetPid = targetProcess.pid;
- print("Sending kill signal to process $targetPid.");
- targetProcess.kill();
- // If the process was already dead exitCode is already
- // available and we call exit() in the next event loop cycle.
- // Otherwise this will wait for the process to exit.
-
- targetProcess.exitCode.then((exitCode) {
- print("Process $targetPid terminated with exit code $exitCode.");
- if (errorsDetected) {
- print("\n===== Errors detected: =====");
- for (int i = 0; i < errors.length; i++) print(errors[i]);
- print("============================\n");
- }
- Program.printCoverage();
- exit(errors.length);
- });
- cleanupDone = true;
- }
-}
-
-
-// Class to buffer wire protocol data from coverage target and
-// break it down to individual json messages.
-class JsonBuffer {
- String buffer = null;
-
- append(String s) {
- if (buffer == null || buffer.length == 0) {
- buffer = s;
- } else {
- buffer = buffer + s;
- }
- }
-
- String getNextMessage() {
- if (buffer == null) return null;
- int msgLen = objectLength();
- if (msgLen == 0) return null;
- String msg = null;
- if (msgLen == buffer.length) {
- msg = buffer;
- buffer = null;
- } else {
- assert(msgLen < buffer.length);
- msg = buffer.substring(0, msgLen);
- buffer = buffer.substring(msgLen);
- }
- return msg;
- }
-
- bool haveGarbage() {
- if (buffer == null || buffer.length == 0) return false;
- var i = 0, char = " ";
- while (i < buffer.length) {
- char = buffer[i];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- i++;
- }
- if (i >= buffer.length) {
- return false;
- } else {
- return char != "{";
- }
- }
-
- // Returns the character length of the next json message in the
- // buffer, or 0 if there is only a partial message in the buffer.
- // The object value must start with '{' and continues to the
- // matching '}'. No attempt is made to otherwise validate the contents
- // as JSON. If it is invalid, a later JSON.decode() will fail.
- int objectLength() {
- int skipWhitespace(int index) {
- while (index < buffer.length) {
- String char = buffer[index];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- index++;
- }
- return index;
- }
- int skipString(int index) {
- assert(buffer[index - 1] == '"');
- while (index < buffer.length) {
- String char = buffer[index];
- if (char == '"') return index + 1;
- if (char == r'\') index++;
- if (index == buffer.length) return index;
- index++;
- }
- return index;
- }
- int index = 0;
- index = skipWhitespace(index);
- // Bail out if the first non-whitespace character isn't '{'.
- if (index == buffer.length || buffer[index] != '{') return 0;
- int nesting = 0;
- while (index < buffer.length) {
- String char = buffer[index++];
- if (char == '{') {
- nesting++;
- } else if (char == '}') {
- nesting--;
- if (nesting == 0) return index;
- } else if (char == '"') {
- // Strings can contain braces. Skip their content.
- index = skipString(index);
- }
- }
- return 0;
- }
-}
-
-
-void main(List<String> arguments) {
- var targetOpts = [ "--debug:0" ];
- for (String str in arguments) {
- switch (str) {
- case "--verbose":
- showDebuggeeOutput = true;
- break;
- case "--wire":
- verboseWire = true;
- break;
- default:
- targetOpts.add(str);
- break;
- }
- }
-
- Process.start(Platform.executable, targetOpts).then((Process process) {
- process.stdin.close();
- debugger = new Debugger(process);
- });
-}
diff --git a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
index 586e643..b797e77 100644
--- a/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
+++ b/tools/dart2js/angular2_testing_deps/CURRENT_ANGULAR_DEPS
@@ -1 +1 @@
-64bd9639a14afd83bf3f03ffe82825be2c8e940c
+e1d7bdcfe7f25156c8a462452db5367b68a02df6
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
deleted file mode 100644
index f14a017..0000000
--- a/tools/ddbg.dart
+++ /dev/null
@@ -1,1496 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// Simple interactive debugger shell that connects to the Dart VM's debugger
-// connection port.
-
-import "dart:convert";
-import "dart:io";
-import "dart:async";
-import "dart:math";
-
-import "ddbg/lib/commando.dart";
-
-class TargetScript {
- // The text of a script.
- String source = null;
-
- // A mapping from line number to source text.
- List<String> lineToSource = null;
-
- // A mapping from token offset to line number.
- Map<int,int> tokenToLine = null;
-}
-
-const UnknownLocation = const {};
-
-class TargetIsolate {
- int id;
- // The location of the last paused event.
- Map pausedLocation = null;
-
- TargetIsolate(this.id);
- bool get isPaused => pausedLocation != null;
- String get pausedUrl => pausedLocation != null ? pausedLocation["url"] : null;
-
- Map<String, TargetScript> scripts = {};
-}
-
-Map<int, TargetIsolate> targetIsolates= new Map<int, TargetIsolate>();
-
-Map<int, Completer> outstandingCommands;
-
-Socket vmSock;
-String vmData;
-var cmdSubscription;
-Commando cmdo;
-var vmSubscription;
-int seqNum = 0;
-
-bool isDebugging = false;
-Process targetProcess = null;
-bool suppressNextExitCode = false;
-
-final verbose = false;
-final printMessages = false;
-
-TargetIsolate currentIsolate;
-TargetIsolate mainIsolate;
-
-int debugPort = 5858;
-
-String formatLocation(Map location) {
- if (location == null) return "";
- var fileName = location["url"].split("/").last;
- return "file: $fileName lib: ${location['libraryId']} token: ${location['tokenOffset']}";
-}
-
-
-Future sendCmd(Map<String, dynamic> cmd) {
- var completer = new Completer.sync();
- int id = cmd["id"];
- outstandingCommands[id] = completer;
- if (verbose) {
- print("sending: '${JSON.encode(cmd)}'");
- }
- vmSock.write(JSON.encode(cmd));
- return completer.future;
-}
-
-
-bool checkCurrentIsolate() {
- if (vmSock == null) {
- print("There is no active script. Try 'help run'.");
- return false;
- }
- if (currentIsolate == null) {
- print('There is no current isolate.');
- return false;
- }
- return true;
-}
-
-
-void setCurrentIsolate(TargetIsolate isolate) {
- if (isolate != currentIsolate) {
- currentIsolate = isolate;
- if (mainIsolate == null) {
- print("Main isolate is ${isolate.id}");
- mainIsolate = isolate;
- }
- print("Current isolate is now ${isolate.id}");
- }
-}
-
-
-bool checkPaused() {
- if (!checkCurrentIsolate()) return false;
- if (currentIsolate.isPaused) return true;
- print("Current isolate must be paused");
- return false;
-}
-
-// These settings are allowed in the 'set' and 'show' debugger commands.
-var validSettings = ['vm', 'vmargs', 'script', 'args'];
-
-// The current values for all settings.
-var settings = new Map();
-
-String _leftJustify(text, int width) {
- StringBuffer buffer = new StringBuffer();
- buffer.write(text);
- while (buffer.length < width) {
- buffer.write(' ');
- }
- return buffer.toString();
-}
-
-// TODO(turnidge): Move all commands here.
-List<Command> commandList =
- [ new HelpCommand(),
- new QuitCommand(),
- new RunCommand(),
- new KillCommand(),
- new ConnectCommand(),
- new DisconnectCommand(),
- new SetCommand(),
- new ShowCommand() ];
-
-
-List<Command> matchCommand(String commandName, bool exactMatchWins) {
- List matches = [];
- for (var command in commandList) {
- if (command.name.startsWith(commandName)) {
- if (exactMatchWins && command.name == commandName) {
- // Exact match
- return [command];
- } else {
- matches.add(command);
- }
- }
- }
- return matches;
-}
-
-abstract class Command {
- String get name;
- Future run(List<String> args);
-}
-
-class HelpCommand extends Command {
- final name = 'help';
- final helpShort = 'Show a list of debugger commands';
- final helpLong ="""
-Show a list of debugger commands or get more information about a
-particular command.
-
-Usage:
- help
- help <command>
-""";
-
- Future run(List<String> args) {
- if (args.length == 1) {
- print("Debugger commands:\n");
- for (var command in commandList) {
- print(' ${_leftJustify(command.name, 11)} ${command.helpShort}');
- }
-
- // TODO(turnidge): Convert all commands to use the Command class.
- print("""
- bt Show backtrace
- r Resume execution
- s Single step
- so Step over
- si Step into
- sbp [<file>] <line> Set breakpoint
- rbp <id> Remove breakpoint with given id
- po <id> Print object info for given id
- eval fr <n> <expr> Evaluate expr on stack frame index n
- eval obj <id> <expr> Evaluate expr on object id
- eval cls <id> <expr> Evaluate expr on class id
- eval lib <id> <expr> Evaluate expr in toplevel of library id
- pl <id> <idx> [<len>] Print list element/slice
- pc <id> Print class info for given id
- ll List loaded libraries
- plib <id> Print library info for given library id
- slib <id> <true|false> Set library id debuggable
- pg <id> Print all global variables visible within given library id
- ls <lib_id> List loaded scripts in library
- gs <lib_id> <script_url> Get source text of script in library
- tok <lib_id> <script_url> Get line and token table of script in library
- epi <none|all|unhandled> Set exception pause info
- li List ids of all isolates in the VM
- sci <id> Set current target isolate
- i <id> Interrupt execution of given isolate id
-""");
-
- print("For more information about a particular command, type:\n\n"
- " help <command>\n");
-
- print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
- } else if (args.length == 2) {
- var commandName = args[1];
- var matches = matchCommand(commandName, true);
- if (matches.length == 0) {
- print("Command '$commandName' not recognized. "
- "Try 'help' for a list of commands.");
- } else {
- for (var command in matches) {
- print("---- ${command.name} ----\n${command.helpLong}");
- }
- }
- } else {
- print("Command '$command' not recognized. "
- "Try 'help' for a list of commands.");
- }
-
- return new Future.value();
- }
-}
-
-
-class QuitCommand extends Command {
- final name = 'quit';
- final helpShort = 'Quit the debugger.';
- final helpLong ="""
-Quit the debugger.
-
-Usage:
- quit
-""";
-
- Future run(List<String> args) {
- if (args.length > 1) {
- print("Unexpected arguments to $name command.");
- return new Future.value();
- }
- return debuggerQuit();
- }
-}
-
-class SetCommand extends Command {
- final name = 'set';
- final helpShort = 'Change the value of a debugger setting.';
- final helpLong ="""
-Change the value of a debugger setting.
-
-Usage:
- set <setting> <value>
-
-Valid settings are:
- ${validSettings.join('\n ')}.
-
-See also 'help show'.
-""";
-
- Future run(List<String> args) {
- if (args.length < 3 || !validSettings.contains(args[1])) {
- print("Undefined $name command. Try 'help $name'.");
- return new Future.value();
- }
- var option = args[1];
- var value = args.getRange(2, args.length).join(' ');
- settings[option] = value;
- return new Future.value();
- }
-}
-
-class ShowCommand extends Command {
- final name = 'show';
- final helpShort = 'Show the current value of a debugger setting.';
- final helpLong ="""
-Show the current value of a debugger setting.
-
-Usage:
- show
- show <setting>
-
-If no <setting> is specified, all current settings are shown.
-
-Valid settings are:
- ${validSettings.join('\n ')}.
-
-See also 'help set'.
-""";
-
- Future run(List<String> args) {
- if (args.length == 1) {
- for (var option in validSettings) {
- var value = settings[option];
- print("$option = '$value'");
- }
- } else if (args.length == 2 && validSettings.contains(args[1])) {
- var option = args[1];
- var value = settings[option];
- if (value == null) {
- print('$option has not been set.');
- } else {
- print("$option = '$value'");
- }
- return new Future.value();
- } else {
- print("Undefined $name command. Try 'help $name'.");
- }
- return new Future.value();
- }
-}
-
-class RunCommand extends Command {
- final name = 'run';
- final helpShort = "Run the currrent script.";
- final helpLong ="""
-Runs the current script.
-
-Usage:
- run
- run <args>
-
-The current script will be run on the current vm. The 'vm' and
-'vmargs' settings are used to specify the current vm and vm arguments.
-The 'script' and 'args' settings are used to specify the current
-script and script arguments.
-
-For more information on settings type 'help show' or 'help set'.
-
-If <args> are provided to the run command, it is the same as typing
-'set args <args>' followed by 'run'.
-""";
-
- Future run(List<String> cmdArgs) {
- if (isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is already a running dart process. "
- "Try 'kill'.");
- return new Future.value();
- }
- assert(targetProcess == null);
- if (settings['script'] == null) {
- print("There is no script specified. "
- "Use 'set script' to set the current script.");
- return new Future.value();
- }
- if (cmdArgs.length > 1) {
- settings['args'] = cmdArgs.getRange(1, cmdArgs.length);
- }
-
- // Build the process arguments.
- var processArgs = ['--debug:$debugPort'];
- if (verbose) {
- processArgs.add('--verbose_debug');
- }
- if (settings['vmargs'] != null) {
- processArgs.addAll(settings['vmargs'].split(' '));
- }
- processArgs.add(settings['script']);
- if (settings['args'] != null) {
- processArgs.addAll(settings['args'].split(' '));
- }
- String vm = settings['vm'];
-
- isDebugging = true;
- cmdo.hide();
- return Process.start(vm, processArgs).then((process) {
- print("Started process ${process.pid} '$vm ${processArgs.join(' ')}'");
- targetProcess = process;
- process.stdin.close();
-
- // TODO(turnidge): For now we only show full lines of output
- // from the debugged process. Should show each character.
- process.stdout
- .transform(UTF8.decoder)
- .transform(new LineSplitter())
- .listen((String line) {
- cmdo.hide();
- // TODO(turnidge): Escape output in any way?
- print(line);
- cmdo.show();
- });
-
- process.stderr
- .transform(UTF8.decoder)
- .transform(new LineSplitter())
- .listen((String line) {
- cmdo.hide();
- print(line);
- cmdo.show();
- });
-
- process.exitCode.then((int exitCode) {
- cmdo.hide();
- if (suppressNextExitCode) {
- suppressNextExitCode = false;
- } else {
- if (exitCode == 0) {
- print('Process exited normally.');
- } else {
- print('Process exited with code $exitCode.');
- }
- }
- targetProcess = null;
- cmdo.show();
- });
-
- // Wait for the vm to open the debugging port.
- return openVmSocket(0);
- });
- }
-}
-
-class KillCommand extends Command {
- final name = 'kill';
- final helpShort = 'Kill the currently executing script.';
- final helpLong ="""
-Kill the currently executing script.
-
-Usage:
- kill
-""";
-
- Future run(List<String> cmdArgs) {
- if (!isDebugging) {
- print('There is no running script.');
- return new Future.value();
- }
- if (targetProcess == null) {
- print("The active dart process was not started with 'run'. "
- "Try 'disconnect' instead.");
- return new Future.value();
- }
- assert(targetProcess != null);
- bool result = targetProcess.kill();
- if (result) {
- print('Process killed.');
- suppressNextExitCode = true;
- } else {
- print('Unable to kill process ${targetProcess.pid}');
- }
- return new Future.value();
- }
-}
-
-class ConnectCommand extends Command {
- final name = 'connect';
- final helpShort = "Connect to a running dart script.";
- final helpLong ="""
-Connect to a running dart script.
-
-Usage:
- connect
- connect <port>
-
-The debugger will connect to a dart script which has already been
-started with the --debug option. If no port is provided, the debugger
-will attempt to connect on the default debugger port.
-""";
-
- Future run(List<String> cmdArgs) {
- if (cmdArgs.length > 2) {
- print("Too many arguments to 'connect'.");
- }
- if (isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is already a running dart process. "
- "Try 'kill'.");
- return new Future.value();
- }
- assert(targetProcess == null);
- if (cmdArgs.length == 2) {
- debugPort = int.parse(cmdArgs[1]);
- }
-
- isDebugging = true;
- cmdo.hide();
- return openVmSocket(0);
- }
-}
-
-class DisconnectCommand extends Command {
- final name = 'disconnect';
- final helpShort = "Disconnect from a running dart script.";
- final helpLong ="""
-Disconnect from a running dart script.
-
-Usage:
- disconnect
-
-The debugger will disconnect from a dart script's debugging port. The
-script must have been connected to earlier with the 'connect' command.
-""";
-
- Future run(List<String> cmdArgs) {
- if (cmdArgs.length > 1) {
- print("Too many arguments to 'disconnect'.");
- }
- if (!isDebugging) {
- // TODO(turnidge): Implement modal y/n dialog to stop running script.
- print("There is no active dart process. "
- "Try 'connect'.");
- return new Future.value();
- }
- if (targetProcess != null) {
- print("The active dart process was started with 'run'. "
- "Try 'kill'.");
- }
-
- cmdo.hide();
- return closeVmSocket();
- }
-}
-
-typedef void HandlerType(Map response);
-
-HandlerType showPromptAfter(void handler(Map response)) {
- return (response) {
- handler(response);
- cmdo.show();
- };
-}
-
-void processCommand(String cmdLine) {
- void huh() {
- print("'$cmdLine' not understood, try 'help' for help.");
- }
-
- cmdo.hide();
- seqNum++;
- cmdLine = cmdLine.trim();
- var args = cmdLine.split(' ');
- if (args.length == 0) {
- return;
- }
- var command = args[0];
-
- var resume_commands =
- { 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
- if (resume_commands[command] != null) {
- if (!checkPaused()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": resume_commands[command],
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
- } else if (command == "bt") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getStackTrace",
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
- } else if (command == "ll") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLibraries",
- "params": { "isolateId" : currentIsolate.id } };
- sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
- } else if (command == "sbp" && args.length >= 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var url, line;
- if (args.length == 2 && currentIsolate.pausedUrl != null) {
- url = currentIsolate.pausedUrl;
- line = int.parse(args[1]);
- } else {
- url = args[1];
- line = int.parse(args[2]);
- }
- var cmd = { "id": seqNum,
- "command": "setBreakpoint",
- "params": { "isolateId" : currentIsolate.id,
- "url": url,
- "line": line }};
- sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
- } else if (command == "rbp" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "removeBreakpoint",
- "params": { "isolateId" : currentIsolate.id,
- "breakpointId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command == "ls" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getScriptURLs",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
- } else if (command == "eval" && args.length > 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var expr = args.getRange(3, args.length).join(" ");
- var target = args[1];
- if (target == "obj") {
- target = "objectId";
- } else if (target == "cls") {
- target = "classId";
- } else if (target == "lib") {
- target = "libraryId";
- } else if (target == "fr") {
- target = "frameId";
- } else {
- huh();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "evaluateExpr",
- "params": { "isolateId": currentIsolate.id,
- target: int.parse(args[2]),
- "expression": expr } };
- sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
- } else if (command == "po" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getObjectProperties",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
- } else if (command == "pl" && args.length >= 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd;
- if (args.length == 3) {
- cmd = { "id": seqNum,
- "command": "getListElements",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]),
- "index": int.parse(args[2]) } };
- } else {
- cmd = { "id": seqNum,
- "command": "getListElements",
- "params": { "isolateId" : currentIsolate.id,
- "objectId": int.parse(args[1]),
- "index": int.parse(args[2]),
- "length": int.parse(args[3]) } };
- }
- sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
- } else if (command == "pc" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getClassProperties",
- "params": { "isolateId" : currentIsolate.id,
- "classId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
- } else if (command == "plib" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLibraryProperties",
- "params": {"isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
- } else if (command == "slib" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "setLibraryProperties",
- "params": {"isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "debuggingEnabled": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
- } else if (command == "pg" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getGlobalVariables",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
- } else if (command == "gs" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getScriptSource",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "url": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
- } else if (command == "tok" && args.length == 3) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "getLineNumberTable",
- "params": { "isolateId" : currentIsolate.id,
- "libraryId": int.parse(args[1]),
- "url": args[2] } };
- sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
- } else if (command == "epi" && args.length == 2) {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum,
- "command": "setPauseOnException",
- "params": { "isolateId" : currentIsolate.id,
- "exceptions": args[1] } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command == "li") {
- if (!checkCurrentIsolate()) {
- cmdo.show();
- return;
- }
- var cmd = { "id": seqNum, "command": "getIsolateIds" };
- sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
- } else if (command == "sci" && args.length == 2) {
- var id = int.parse(args[1]);
- if (targetIsolates[id] != null) {
- setCurrentIsolate(targetIsolates[id]);
- } else {
- print("$id is not a valid isolate id");
- }
- cmdo.show();
- } else if (command == "i" && args.length == 2) {
- var cmd = { "id": seqNum,
- "command": "interrupt",
- "params": { "isolateId": int.parse(args[1]) } };
- sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
- } else if (command.length == 0) {
- huh();
- cmdo.show();
- } else {
- // TODO(turnidge): Use this for all commands.
- var matches = matchCommand(command, true);
- if (matches.length == 0) {
- huh();
- cmdo.show();
- } else if (matches.length == 1) {
- matches[0].run(args).then((_) {
- cmdo.show();
- });
- } else {
- var matchNames = matches.map((handler) => handler.name);
- print("Ambiguous command '$command' : ${matchNames.toList()}");
- cmdo.show();
- }
- }
-}
-
-
-void processError(error, trace) {
- cmdo.hide();
- print("\nInternal error:\n$error\n$trace");
- cmdo.show();
-}
-
-
-void processDone() {
- debuggerQuit();
-}
-
-
-String remoteObject(value) {
- var kind = value["kind"];
- var text = value["text"];
- var id = value["objectId"];
- if (kind == "string") {
- return "(string, id $id) '$text'";
- } else if (kind == "list") {
- var len = value["length"];
- return "(list, id $id, len $len) $text";
- } else if (kind == "object") {
- return "(obj, id $id) $text";
- } else if (kind == "function") {
- var location = formatLocation(value['location']);
- var name = value['name'];
- var signature = value['signature'];
- return "(closure ${name}${signature} $location)";
- } else {
- return "$text";
- }
-}
-
-
-printNamedObject(obj) {
- var name = obj["name"];
- var value = obj["value"];
- print(" $name = ${remoteObject(value)}");
-}
-
-
-handleGetObjPropsResponse(Map response) {
- Map props = response["result"];
- int class_id = props["classId"];
- if (class_id == -1) {
- print(" null");
- return;
- }
- List fields = props["fields"];
- print(" class id: $class_id");
- for (int i = 0; i < fields.length; i++) {
- printNamedObject(fields[i]);
- }
-}
-
-handleGetListResponse(Map response) {
- Map result = response["result"];
- if (result["elements"] != null) {
- // List slice.
- var index = result["index"];
- var length = result["length"];
- List elements = result["elements"];
- assert(length == elements.length);
- for (int i = 0; i < length; i++) {
- var kind = elements[i]["kind"];
- var text = elements[i]["text"];
- print(" ${index + i}: ($kind) $text");
- }
- } else {
- // One element, a remote object.
- print(result);
- print(" ${remoteObject(result)}");
- }
-}
-
-
-handleGetClassPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["name"] != null);
- int libId = props["libraryId"];
- assert(libId != null);
- print(" class ${props["name"]} (library id: $libId)");
- List fields = props["fields"];
- if (fields.length > 0) {
- print(" static fields:");
- for (int i = 0; i < fields.length; i++) {
- printNamedObject(fields[i]);
- }
- }
-}
-
-
-handleGetLibraryPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["url"] != null);
- print(" library url: ${props["url"]}");
- assert(props["debuggingEnabled"] != null);
- print(" debugging enabled: ${props["debuggingEnabled"]}");
- List imports = props["imports"];
- assert(imports != null);
- if (imports.length > 0) {
- print(" imports:");
- for (int i = 0; i < imports.length; i++) {
- print(" id ${imports[i]["libraryId"]} prefix ${imports[i]["prefix"]}");
- }
- }
- List globals = props["globals"];
- assert(globals != null);
- if (globals.length > 0) {
- print(" global variables:");
- for (int i = 0; i < globals.length; i++) {
- printNamedObject(globals[i]);
- }
- }
-}
-
-
-handleSetLibraryPropsResponse(Map response) {
- Map props = response["result"];
- assert(props["debuggingEnabled"] != null);
- print(" debugging enabled: ${props["debuggingEnabled"]}");
-}
-
-
-handleGetGlobalVarsResponse(Map response) {
- List globals = response["result"]["globals"];
- for (int i = 0; i < globals.length; i++) {
- printNamedObject(globals[i]);
- }
-}
-
-
-handleGetSourceResponse(Map response) {
- Map result = response["result"];
- String source = result["text"];
- print("Source text:\n$source\n--------");
-}
-
-
-handleGetLineTableResponse(Map response) {
- Map result = response["result"];
- var info = result["lines"];
- print("Line info table:\n$info");
-}
-
-
-void handleGetIsolatesResponse(Map response) {
- Map result = response["result"];
- List ids = result["isolateIds"];
- assert(ids != null);
- print("List of isolates:");
- for (int id in ids) {
- TargetIsolate isolate = targetIsolates[id];
- var state = (isolate != null) ? "running" : "<unknown isolate>";
- if (isolate != null && isolate.isPaused) {
- var loc = formatLocation(isolate.pausedLocation);
- state = "paused at $loc";
- }
- var marker = " ";
- if (currentIsolate != null && id == currentIsolate.id) {
- marker = "*";
- }
- print("$marker $id $state");
- }
-}
-
-
-void handleGetLibraryResponse(Map response) {
- Map result = response["result"];
- List libs = result["libraries"];
- print("Loaded libraries:");
- print(libs);
- for (int i = 0; i < libs.length; i++) {
- print(" ${libs[i]["id"]} ${libs[i]["url"]}");
- }
-}
-
-
-void handleGetScriptsResponse(Map response) {
- Map result = response["result"];
- List urls = result["urls"];
- print("Loaded scripts:");
- for (int i = 0; i < urls.length; i++) {
- print(" $i ${urls[i]}");
- }
-}
-
-
-void handleEvalResponse(Map response) {
- Map result = response["result"];
- print(remoteObject(result));
-}
-
-
-void handleSetBpResponse(Map response) {
- Map result = response["result"];
- var id = result["breakpointId"];
- assert(id != null);
- print("Set BP $id");
-}
-
-
-void handleGenericResponse(Map response) {
- if (response["error"] != null) {
- print("Error: ${response["error"]}");
- }
-}
-
-void handleResumedResponse(Map response) {
- if (response["error"] != null) {
- print("Error: ${response["error"]}");
- return;
- }
- assert(currentIsolate != null);
- currentIsolate.pausedLocation = null;
-}
-
-
-void handleStackTraceResponse(Map response) {
- Map result = response["result"];
- List callFrames = result["callFrames"];
- assert(callFrames != null);
- printStackTrace(callFrames);
-}
-
-
-void printStackFrame(frame_num, Map frame) {
- var fname = frame["functionName"];
- var loc = formatLocation(frame["location"]);
- print("#${_leftJustify(frame_num,2)} $fname at $loc");
- List locals = frame["locals"];
- for (int i = 0; i < locals.length; i++) {
- printNamedObject(locals[i]);
- }
-}
-
-
-void printStackTrace(List frames) {
- for (int i = 0; i < frames.length; i++) {
- printStackFrame(i, frames[i]);
- }
-}
-
-
-Map<int, int> parseLineNumberTable(List<List<int>> table) {
- Map tokenToLine = {};
- for (var line in table) {
- // Each entry begins with a line number...
- var lineNumber = line[0];
- for (var pos = 1; pos < line.length; pos += 2) {
- // ...and is followed by (token offset, col number) pairs.
- // We ignore the column numbers.
- var tokenOffset = line[pos];
- tokenToLine[tokenOffset] = lineNumber;
- }
- }
- return tokenToLine;
-}
-
-
-Future<TargetScript> getTargetScript(Map location) {
- var isolate = targetIsolates[currentIsolate.id];
- var url = location['url'];
- var script = isolate.scripts[url];
- if (script != null) {
- return new Future.value(script);
- }
- script = new TargetScript();
-
- // Ask the vm for the source and line number table.
- var sourceCmd = {
- "id": seqNum++,
- "command": "getScriptSource",
- "params": { "isolateId": currentIsolate.id,
- "libraryId": location['libraryId'],
- "url": url } };
-
- var lineNumberCmd = {
- "id": seqNum++,
- "command": "getLineNumberTable",
- "params": { "isolateId": currentIsolate.id,
- "libraryId": location['libraryId'],
- "url": url } };
-
- // Send the source command
- var sourceResponse = sendCmd(sourceCmd).then((response) {
- Map result = response["result"];
- script.source = result['text'];
- // Line numbers are 1-based so add a dummy for line 0.
- script.lineToSource = [''];
- script.lineToSource.addAll(script.source.split('\n'));
- });
-
- // Send the line numbers command
- var lineNumberResponse = sendCmd(lineNumberCmd).then((response) {
- Map result = response["result"];
- script.tokenToLine = parseLineNumberTable(result['lines']);
- });
-
- return Future.wait([sourceResponse, lineNumberResponse]).then((_) {
- // When both commands complete, cache the result.
- isolate.scripts[url] = script;
- return script;
- });
-}
-
-
-Future printLocation(String label, Map location) {
- // Figure out the line number.
- return getTargetScript(location).then((script) {
- var lineNumber = script.tokenToLine[location['tokenOffset']];
- var text = script.lineToSource[lineNumber];
- if (label != null) {
- var fileName = location['url'].split("/").last;
- print("$label \n"
- " at $fileName:$lineNumber");
- }
- print("${_leftJustify(lineNumber, 8)}$text");
- });
-}
-
-
-Future handlePausedEvent(msg) {
- assert(msg["params"] != null);
- var reason = msg["params"]["reason"];
- int isolateId = msg["params"]["isolateId"];
- assert(isolateId != null);
- var isolate = targetIsolates[isolateId];
- assert(isolate != null);
- assert(!isolate.isPaused);
- var location = msg["params"]["location"];;
- setCurrentIsolate(isolate);
- isolate.pausedLocation = (location == null) ? UnknownLocation : location;
- if (reason == "breakpoint") {
- assert(location != null);
- var bpId = (msg["params"]["breakpointId"]);
- var label = (bpId != null) ? "Breakpoint $bpId" : null;
- return printLocation(label, location);
- } else if (reason == "interrupted") {
- assert(location != null);
- return printLocation("Interrupted", location);
- } else {
- assert(reason == "exception");
- var excObj = msg["params"]["exception"];
- print("Isolate $isolateId paused on exception");
- print(remoteObject(excObj));
- return new Future.value();
- }
-}
-
-void handleIsolateEvent(msg) {
- Map params = msg["params"];
- assert(params != null);
- var isolateId = params["id"];
- var reason = params["reason"];
- if (reason == "created") {
- print("Isolate $isolateId has been created.");
- assert(targetIsolates[isolateId] == null);
- targetIsolates[isolateId] = new TargetIsolate(isolateId);
- } else {
- assert(reason == "shutdown");
- var isolate = targetIsolates.remove(isolateId);
- assert(isolate != null);
- if (isolate == mainIsolate) {
- mainIsolate = null;
- print("Main isolate ${isolate.id} has terminated.");
- } else {
- print("Isolate ${isolate.id} has terminated.");
- }
- if (isolate == currentIsolate) {
- currentIsolate = mainIsolate;
- if (currentIsolate == null && !targetIsolates.isEmpty) {
- currentIsolate = targetIsolates.values.first;
- }
- if (currentIsolate != null) {
- print("Setting current isolate to ${currentIsolate.id}.");
- } else {
- print("All isolates have terminated.");
- }
- }
- }
-}
-
-void processVmMessage(String jsonString) {
- var msg = JSON.decode(jsonString);
- if (msg == null) {
- return;
- }
- var event = msg["event"];
- if (event == "isolate") {
- cmdo.hide();
- handleIsolateEvent(msg);
- cmdo.show();
- return;
- }
- if (event == "paused") {
- cmdo.hide();
- handlePausedEvent(msg).then((_) {
- cmdo.show();
- });
- return;
- }
- if (event == "breakpointResolved") {
- Map params = msg["params"];
- assert(params != null);
- var isolateId = params["isolateId"];
- var location = formatLocation(params["location"]);
- cmdo.hide();
- print("Breakpoint ${params["breakpointId"]} resolved in isolate $isolateId"
- " at $location.");
- cmdo.show();
- return;
- }
- if (msg["id"] != null) {
- var id = msg["id"];
- if (outstandingCommands.containsKey(id)) {
- var completer = outstandingCommands.remove(id);
- if (msg["error"] != null) {
- print("VM says: ${msg["error"]}");
- // TODO(turnidge): Rework how hide/show happens. For now we
- // show here explicitly.
- cmdo.show();
- } else {
- completer.complete(msg);
- }
- }
- }
-}
-
-bool haveGarbageVmData() {
- if (vmData == null || vmData.length == 0) return false;
- var i = 0, char = " ";
- while (i < vmData.length) {
- char = vmData[i];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- i++;
- }
- if (i >= vmData.length) {
- return false;
- } else {
- return char != "{";
- }
-}
-
-
-void processVmData(String data) {
- if (vmData == null || vmData.length == 0) {
- vmData = data;
- } else {
- vmData = vmData + data;
- }
- if (haveGarbageVmData()) {
- print("Error: have garbage data from VM: '$vmData'");
- return;
- }
- int msg_len = jsonObjectLength(vmData);
- if (printMessages && msg_len == 0) {
- print("have partial or illegal json message"
- " of ${vmData.length} chars:\n'$vmData'");
- return;
- }
- while (msg_len > 0 && msg_len <= vmData.length) {
- if (msg_len == vmData.length) {
- if (printMessages) { print("have one full message:\n$vmData"); }
- processVmMessage(vmData);
- vmData = null;
- return;
- }
- if (printMessages) { print("at least one message: '$vmData'"); }
- var msg = vmData.substring(0, msg_len);
- if (printMessages) { print("first message: $msg"); }
- vmData = vmData.substring(msg_len);
- if (haveGarbageVmData()) {
- print("Error: garbage data after previous message: '$vmData'");
- print("Previous message was: '$msg'");
- return;
- }
- processVmMessage(msg);
- msg_len = jsonObjectLength(vmData);
- }
- if (printMessages) { print("leftover vm data '$vmData'"); }
-}
-
-/**
- * Skip past a JSON object value.
- * The object value must start with '{' and continues to the
- * matching '}'. No attempt is made to otherwise validate the contents
- * as JSON. If it is invalid, a later [parseJson] will fail.
- */
-int jsonObjectLength(String string) {
- int skipWhitespace(int index) {
- while (index < string.length) {
- String char = string[index];
- if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
- index++;
- }
- return index;
- }
- int skipString(int index) {
- assert(string[index - 1] == '"');
- while (index < string.length) {
- String char = string[index];
- if (char == '"') return index + 1;
- if (char == r'\') index++;
- if (index == string.length) return index;
- index++;
- }
- return index;
- }
- int index = 0;
- index = skipWhitespace(index);
- // Bail out if the first non-whitespace character isn't '{'.
- if (index == string.length || string[index] != '{') return 0;
- int nesting = 0;
- while (index < string.length) {
- String char = string[index++];
- if (char == '{') {
- nesting++;
- } else if (char == '}') {
- nesting--;
- if (nesting == 0) return index;
- } else if (char == '"') {
- // Strings can contain braces. Skip their content.
- index = skipString(index);
- }
- }
- return 0;
-}
-
-List<String> debuggerCommandCompleter(List<String> commandParts) {
- List<String> completions = new List<String>();
-
- // TODO(turnidge): Have a global command table and use it to for
- // help messages, command completion, and command dispatching. For now
- // we hardcode the list here.
- //
- // TODO(turnidge): Implement completion for arguments as well.
- List<String> oldCommands = ['bt', 'r', 's', 'so', 'si', 'sbp', 'rbp',
- 'po', 'eval', 'pl', 'pc', 'll', 'plib', 'slib',
- 'pg', 'ls', 'gs', 'tok', 'epi', 'li', 'i' ];
-
- // Completion of first word in the command.
- if (commandParts.length == 1) {
- String prefix = commandParts.last;
- for (var command in oldCommands) {
- if (command.startsWith(prefix)) {
- completions.add(command);
- }
- }
- for (var command in commandList) {
- if (command.name.startsWith(prefix)) {
- completions.add(command.name);
- }
- }
- }
-
- return completions;
-}
-
-Future closeCommando() {
- var subscription = cmdSubscription;
- cmdSubscription = null;
- cmdo = null;
-
- var future = subscription.cancel();
- if (future != null) {
- return future;
- } else {
- return new Future.value();
- }
-}
-
-
-Future openVmSocket(int attempt) {
- return Socket.connect("127.0.0.1", debugPort).then(
- setupVmSocket,
- onError: (e) {
- // We were unable to connect to the debugger's port. Try again.
- retryOpenVmSocket(e, attempt);
- });
-}
-
-
-void setupVmSocket(Socket s) {
- vmSock = s;
- vmSock.setOption(SocketOption.TCP_NODELAY, true);
- var stringStream = vmSock.transform(UTF8.decoder);
- outstandingCommands = new Map<int, Completer>();
- vmSubscription = stringStream.listen(
- (String data) {
- processVmData(data);
- },
- onDone: () {
- cmdo.hide();
- if (verbose) {
- print("VM debugger connection closed");
- }
- closeVmSocket().then((_) {
- cmdo.show();
- });
- },
- onError: (err) {
- cmdo.hide();
- // TODO(floitsch): do we want to print the stack trace?
- print("Error in debug connection: $err");
-
- // TODO(turnidge): Kill the debugged process here?
- closeVmSocket().then((_) {
- cmdo.show();
- });
- });
-}
-
-
-Future retryOpenVmSocket(error, int attempt) {
- var delay;
- if (attempt < 10) {
- delay = new Duration(milliseconds:10);
- } else if (attempt < 20) {
- delay = new Duration(seconds:1);
- } else {
- // Too many retries. Give up.
- //
- // TODO(turnidge): Kill the debugged process here?
- print('Timed out waiting for debugger to start.\nError: $e');
- return closeVmSocket();
- }
- // Wait and retry.
- return new Future.delayed(delay, () {
- openVmSocket(attempt + 1);
- });
-}
-
-
-Future closeVmSocket() {
- if (vmSubscription == null) {
- // Already closed, nothing to do.
- assert(vmSock == null);
- return new Future.value();
- }
-
- isDebugging = false;
- var subscription = vmSubscription;
- var sock = vmSock;
-
- // Wait for the socket to close and the subscription to be
- // cancelled. Perhaps overkill, but it means we know these will be
- // done.
- //
- // This is uglier than it needs to be since cancel can return null.
- var cleanupFutures = [sock.close()];
- var future = subscription.cancel();
- if (future != null) {
- cleanupFutures.add(future);
- }
-
- vmSubscription = null;
- vmSock = null;
- outstandingCommands = null;
- return Future.wait(cleanupFutures);
-}
-
-void debuggerError(self, parent, zone, error, StackTrace trace) {
- print('\n--------\nExiting due to unexpected error:\n'
- ' $error\n$trace\n');
- debuggerQuit();
-}
-
-Future debuggerQuit() {
- // Kill target process, if any.
- if (targetProcess != null) {
- if (!targetProcess.kill()) {
- print('Unable to kill process ${targetProcess.pid}');
- }
- }
-
- // Restore terminal settings, close connections.
- return Future.wait([closeCommando(), closeVmSocket()]).then((_) {
- exit(0);
-
- // Unreachable.
- return new Future.value();
- });
-}
-
-
-void parseArgs(List<String> args) {
- int pos = 0;
- settings['vm'] = Platform.executable;
- while (pos < args.length && args[pos].startsWith('-')) {
- pos++;
- }
- if (pos < args.length) {
- settings['vmargs'] = args.getRange(0, pos).join(' ');
- settings['script'] = args[pos];
- settings['args'] = args.getRange(pos + 1, args.length).join(' ');
- }
-}
-
-void main(List<String> args) {
- // Setup a zone which will exit the debugger cleanly on any uncaught
- // exception.
- var zone = Zone.ROOT.fork(specification:new ZoneSpecification(
- handleUncaughtError: debuggerError));
-
- zone.run(() {
- parseArgs(args);
- cmdo = new Commando(completer: debuggerCommandCompleter);
- cmdSubscription = cmdo.commands.listen(processCommand,
- onError: processError,
- onDone: processDone);
- });
-}
diff --git a/tools/ddbg/lib/commando.dart b/tools/ddbg/lib/commando.dart
deleted file mode 100644
index f3ff3ea..0000000
--- a/tools/ddbg/lib/commando.dart
+++ /dev/null
@@ -1,731 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-import 'terminfo.dart';
-
-typedef List<String> CommandCompleter(List<String> commandParts);
-
-class Commando {
- // Ctrl keys
- static const runeCtrlA = 0x01;
- static const runeCtrlB = 0x02;
- static const runeCtrlD = 0x04;
- static const runeCtrlE = 0x05;
- static const runeCtrlF = 0x06;
- static const runeTAB = 0x09;
- static const runeNewline = 0x0a;
- static const runeCtrlK = 0x0b;
- static const runeCtrlL = 0x0c;
- static const runeCtrlN = 0x0e;
- static const runeCtrlP = 0x10;
- static const runeCtrlU = 0x15;
- static const runeCtrlY = 0x19;
- static const runeESC = 0x1b;
- static const runeSpace = 0x20;
- static const runeDEL = 0x7F;
-
- StreamController<String> _commandController;
-
- Stream get commands => _commandController.stream;
-
- Commando({consoleIn,
- consoleOut,
- this.prompt : '> ',
- this.completer : null}) {
- _stdin = (consoleIn != null ? consoleIn : stdin);
- _stdout = (consoleOut != null ? consoleOut : stdout);
- _commandController = new StreamController<String>(
- onCancel: _onCancel);
- _stdin.echoMode = false;
- _stdin.lineMode = false;
- _screenWidth = _term.cols - 1;
- _writePrompt();
- // TODO(turnidge): Handle errors in _stdin here.
- _stdinSubscription =
- _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
- }
-
- Future _onCancel() {
- _stdin.echoMode = true;
- _stdin.lineMode = true;
- var future = _stdinSubscription.cancel();
- if (future != null) {
- return future;
- } else {
- return new Future.value();
- }
- }
-
- // Before terminating, call close() to restore terminal settings.
- void _done() {
- _onCancel().then((_) {
- _commandController.close();
- });
- }
-
- void _handleText(String text) {
- try {
- if (!_promptShown) {
- _bufferedInput.write(text);
- return;
- }
-
- var runes = text.runes.toList();
- var pos = 0;
- while (pos < runes.length) {
- if (!_promptShown) {
- // A command was processed which hid the prompt. Buffer
- // the rest of the input.
- //
- // TODO(turnidge): Here and elsewhere in the file I pass
- // runes to String.fromCharCodes. Does this work?
- _bufferedInput.write(
- new String.fromCharCodes(runes.skip(pos)));
- return;
- }
-
- var rune = runes[pos];
-
- // Count consecutive tabs because double-tab is meaningful.
- if (rune == runeTAB) {
- _tabCount++;
- } else {
- _tabCount = 0;
- }
-
- if (_isControlRune(rune)) {
- pos += _handleControlSequence(runes, pos);
- } else {
- pos += _handleRegularSequence(runes, pos);
- }
- }
- } catch(e, trace) {
- _commandController.addError(e, trace);
- }
- }
-
- int _handleControlSequence(List<int> runes, int pos) {
- var runesConsumed = 1; // Most common result.
- var char = runes[pos];
- switch (char) {
- case runeCtrlA:
- _home();
- break;
-
- case runeCtrlB:
- _leftArrow();
- break;
-
- case runeCtrlD:
- if (_currentLine.length == 0) {
- // ^D on an empty line means quit.
- _stdout.writeln("^D");
- _done();
- } else {
- _delete();
- }
- break;
-
- case runeCtrlE:
- _end();
- break;
-
- case runeCtrlF:
- _rightArrow();
- break;
-
- case runeTAB:
- if (_complete(_tabCount > 1)) {
- _tabCount = 0;
- }
- break;
-
- case runeNewline:
- _newline();
- break;
-
- case runeCtrlK:
- _kill();
- break;
-
- case runeCtrlL:
- _clearScreen();
- break;
-
- case runeCtrlN:
- _historyNext();
- break;
-
- case runeCtrlP:
- _historyPrevious();
- break;
-
- case runeCtrlU:
- _clearLine();
- break;
-
- case runeCtrlY:
- _yank();
- break;
-
- case runeESC:
- // Check to see if this is an arrow key.
- if (pos + 2 < runes.length && // must be a 3 char sequence.
- runes[pos + 1] == 0x5b) { // second char must be '['.
- switch (runes[pos + 2]) {
- case 0x41: // ^[[A = up arrow
- _historyPrevious();
- runesConsumed = 3;
- break;
-
- case 0x42: // ^[[B = down arrow
- _historyNext();
- runesConsumed = 3;
- break;
-
- case 0x43: // ^[[C = right arrow
- _rightArrow();
- runesConsumed = 3;
- break;
-
- case 0x44: // ^[[D = left arrow
- _leftArrow();
- runesConsumed = 3;
- break;
-
- default:
- // Ignore the escape character.
- break;
- }
- }
- break;
-
- case runeDEL:
- _backspace();
- break;
-
- default:
- // Ignore the escape character.
- break;
- }
- return runesConsumed;
- }
-
- int _handleRegularSequence(List<int> runes, int pos) {
- var len = pos + 1;
- while (len < runes.length && !_isControlRune(runes[len])) {
- len++;
- }
- _addChars(runes.getRange(pos, len));
- return len;
- }
-
- bool _isControlRune(int char) {
- return (char >= 0x00 && char < 0x20) || (char == 0x7f);
- }
-
- void _writePromptAndLine() {
- _writePrompt();
- var pos = _writeRange(_currentLine, 0, _currentLine.length);
- _cursorPos = _move(pos, _cursorPos);
- }
-
- void _writePrompt() {
- _stdout.write(prompt);
- }
-
- void _addChars(Iterable<int> chars) {
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(chars)
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos + chars.length));
- }
-
- void _backspace() {
- if (_cursorPos == 0) {
- return;
- }
-
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos - 1))
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos - 1));
- }
-
- void _delete() {
- if (_cursorPos == _currentLine.length) {
- return;
- }
-
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(_currentLine.skip(_cursorPos + 1));
- _update(newLine, _cursorPos);
- }
-
- void _home() {
- _updatePos(0);
- }
-
- void _end() {
- _updatePos(_currentLine.length);
- }
-
- void _clearScreen() {
- _stdout.write(_term.clear);
- _term.resize();
- _screenWidth = _term.cols - 1;
- _writePromptAndLine();
- }
-
- void _kill() {
- var newLine = [];
- newLine.addAll(_currentLine.take(_cursorPos));
- _killBuffer = _currentLine.skip(_cursorPos).toList();
- _update(newLine, _cursorPos);
- }
-
- void _clearLine() {
- _update([], 0);
- }
-
- void _yank() {
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(_killBuffer)
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos + _killBuffer.length));
- }
-
- static String _trimLeadingSpaces(String line) {
- bool _isSpace(int rune) {
- return rune == runeSpace;
- }
- return new String.fromCharCodes(line.runes.skipWhile(_isSpace));
- }
-
- static String _sharedPrefix(String one, String two) {
- var len = min(one.length, two.length);
- var runesOne = one.runes.toList();
- var runesTwo = two.runes.toList();
- var pos;
- for (pos = 0; pos < len; pos++) {
- if (runesOne[pos] != runesTwo[pos]) {
- break;
- }
- }
- var shared = new String.fromCharCodes(runesOne.take(pos));
- return shared;
- }
-
- bool _complete(bool showCompletions) {
- if (completer == null) {
- return false;
- }
-
- var linePrefix = _currentLine.take(_cursorPos).toList();
- List<String> commandParts =
- _trimLeadingSpaces(new String.fromCharCodes(linePrefix)).split(' ');
- List<String> completionList = completer(commandParts);
- var completion = '';
-
- if (completionList.length == 0) {
- // The current line admits no possible completion.
- return false;
-
- } else if (completionList.length == 1) {
- // There is a single, non-ambiguous completion for the current line.
- completion = completionList[0];
-
- // If we are at the end of the line, add a space to signal that
- // the completion is unambiguous.
- if (_currentLine.length == _cursorPos) {
- completion = completion + ' ';
- }
- } else {
- // There are ambiguous completions. Find the longest common
- // shared prefix of all of the completions.
- completion = completionList.fold(completionList[0], _sharedPrefix);
- }
-
- var lastWord = commandParts.last;
- if (completion == lastWord) {
- // The completion does not add anything.
- if (showCompletions) {
- // User hit double-TAB. Show them all possible completions.
- _move(_cursorPos, _currentLine.length);
- _stdout.writeln();
- _stdout.writeln(completionList);
- _writePromptAndLine();
- }
- return false;
- } else {
- // Apply the current completion.
- var completionRunes = completion.runes.toList();
-
- var newLine = [];
- newLine..addAll(linePrefix)
- ..addAll(completionRunes.skip(lastWord.length))
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, _cursorPos + completionRunes.length - lastWord.length);
- return true;
- }
- }
-
- void _newline() {
- _addLineToHistory(_currentLine);
- _linePos = _lines.length;
-
- _end();
- _stdout.writeln();
-
- // Call the user's command handler.
- _commandController.add(new String.fromCharCodes(_currentLine));
-
- _currentLine = [];
- _cursorPos = 0;
- if (_promptShown) {
- _writePrompt();
- }
- }
-
- void _leftArrow() {
- _updatePos(_cursorPos - 1);
- }
-
- void _rightArrow() {
- _updatePos(_cursorPos + 1);
- }
-
- void _addLineToHistory(List<int> line) {
- if (_tempLineAdded) {
- _lines.removeLast();
- _tempLineAdded = false;
- }
- if (line.length > 0) {
- _lines.add(line);
- }
- }
-
- void _addTempLineToHistory(List<int> line) {
- _lines.add(line);
- _tempLineAdded = true;
- }
-
- void _replaceHistory(List<int> line, int linePos) {
- _lines[linePos] = line;
- }
-
- void _historyPrevious() {
- if (_linePos == 0) {
- return;
- }
-
- if (_linePos == _lines.length) {
- // The current in-progress line gets temporarily stored in history.
- _addTempLineToHistory(_currentLine);
- } else {
- // Any edits get committed to history.
- _replaceHistory(_currentLine, _linePos);
- }
-
- _linePos -= 1;
- var line = _lines[_linePos];
- _update(line, line.length);
- }
-
- void _historyNext() {
- // For the very first command, _linePos (0) will exceed
- // (_lines.length - 1) (-1) so we use a ">=" here instead of an "==".
- if (_linePos >= (_lines.length - 1)) {
- return;
- }
-
- // Any edits get committed to history.
- _replaceHistory(_currentLine, _linePos);
-
- _linePos += 1;
- var line = _lines[_linePos];
- _update(line, line.length);
- }
-
- void _updatePos(int newCursorPos) {
- if (newCursorPos < 0) {
- return;
- }
- if (newCursorPos > _currentLine.length) {
- return;
- }
-
- _cursorPos = _move(_cursorPos, newCursorPos);
- }
-
- void _update(List<int> newLine, int newCursorPos) {
- var pos = _cursorPos;
- var diffPos;
- var sharedLen = min(_currentLine.length, newLine.length);
-
- // Find first difference.
- for (diffPos = 0; diffPos < sharedLen; diffPos++) {
- if (_currentLine[diffPos] != newLine[diffPos]) {
- break;
- }
- }
-
- // Move the cursor to where the difference begins.
- pos = _move(pos, diffPos);
-
- // Write the new text.
- pos = _writeRange(newLine, pos, newLine.length);
-
- // Clear any extra characters at the end.
- pos = _clearRange(pos, _currentLine.length);
-
- // Move the cursor back to the input point.
- _cursorPos = _move(pos, newCursorPos);
- _currentLine = newLine;
- }
-
- void hide() {
- if (!_promptShown) {
- return;
- }
- _promptShown = false;
- // We need to erase everything, including the prompt.
- var curLine = _getLine(_cursorPos);
- var lastLine = _getLine(_currentLine.length);
-
- // Go to last line.
- if (curLine < lastLine) {
- for (var i = 0; i < (lastLine - curLine); i++) {
- // This moves us to column 0.
- _stdout.write(_term.cursorDown);
- }
- curLine = lastLine;
- } else {
- // Move to column 0.
- _stdout.write('\r');
- }
-
- // Work our way up, clearing lines.
- while (true) {
- _stdout.write(_term.clrEOL);
- if (curLine > 0) {
- _stdout.write(_term.cursorUp);
- } else {
- break;
- }
- }
- }
-
- void show() {
- if (_promptShown) {
- return;
- }
- _promptShown = true;
- _writePromptAndLine();
-
- // If input was buffered while the prompt was hidden, process it
- // now.
- if (!_bufferedInput.isEmpty) {
- var input = _bufferedInput.toString();
- _bufferedInput.clear();
- _handleText(input);
- }
- }
-
- int _writeRange(List<int> text, int pos, int writeToPos) {
- if (pos >= writeToPos) {
- return pos;
- }
- while (pos < writeToPos) {
- var margin = _nextMargin(pos);
- var limit = min(writeToPos, margin);
- _stdout.write(new String.fromCharCodes(text.getRange(pos, limit)));
- pos = limit;
- if (pos == margin) {
- _stdout.write('\n');
- }
- }
- return pos;
- }
-
- int _clearRange(int pos, int clearToPos) {
- if (pos >= clearToPos) {
- return pos;
- }
- while (true) {
- var limit = _nextMargin(pos);
- _stdout.write(_term.clrEOL);
- if (limit >= clearToPos) {
- return pos;
- }
- _stdout.write('\n');
- pos = limit;
- }
- }
-
- int _move(int pos, int newPos) {
- if (pos == newPos) {
- return pos;
- }
-
- var curCol = _getCol(pos);
- var curLine = _getLine(pos);
- var newCol = _getCol(newPos);
- var newLine = _getLine(newPos);
-
- if (curLine > newLine) {
- for (var i = 0; i < (curLine - newLine); i++) {
- _stdout.write(_term.cursorUp);
- }
- }
- if (curLine < newLine) {
- for (var i = 0; i < (newLine - curLine); i++) {
- _stdout.write(_term.cursorDown);
- }
-
- // Moving down resets column to zero, oddly.
- curCol = 0;
- }
- if (curCol > newCol) {
- for (var i = 0; i < (curCol - newCol); i++) {
- _stdout.write(_term.cursorBack);
- }
- }
- if (curCol < newCol) {
- for (var i = 0; i < (newCol - curCol); i++) {
- _stdout.write(_term.cursorForward);
- }
- }
-
- return newPos;
- }
-
- int _nextMargin(int pos) {
- var truePos = pos + prompt.length;
- return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
- }
-
- int _getLine(int pos) {
- var truePos = pos + prompt.length;
- return truePos ~/ _screenWidth;
- }
-
- int _getCol(int pos) {
- var truePos = pos + prompt.length;
- return truePos % _screenWidth;
- }
-
- Stdin _stdin;
- StreamSubscription _stdinSubscription;
- IOSink _stdout;
- final String prompt;
- bool _promptShown = true;
- final CommandCompleter completer;
- TermInfo _term = new TermInfo();
-
- // TODO(turnidge): See if we can get screen resize events.
- int _screenWidth;
- List<int> _currentLine = []; // A list of runes.
- StringBuffer _bufferedInput = new StringBuffer();
- List<List<int>> _lines = [];
-
- // When using the command history, the current line is temporarily
- // added to the history to allow the user to return to it. This
- // values tracks whether the history has a temporary line at the end.
- bool _tempLineAdded = false;
- int _linePos = 0;
- int _cursorPos = 0;
- int _tabCount = 0;
- List<int> _killBuffer = [];
-}
-
-
-// Demo code.
-
-
-List<String> _myCompleter(List<String> commandTokens) {
- List<String> completions = new List<String>();
-
- // First word completions.
- if (commandTokens.length <= 1) {
- String prefix = '';
- if (commandTokens.length == 1) {
- prefix = commandTokens.first;
- }
- if ('quit'.startsWith(prefix)) {
- completions.add('quit');
- }
- if ('help'.startsWith(prefix)) {
- completions.add('help');
- }
- if ('happyface'.startsWith(prefix)) {
- completions.add('happyface');
- }
- }
-
- // Complete 'foobar' or 'gondola' anywhere in string.
- String lastWord = commandTokens.last;
- if ('foobar'.startsWith(lastWord)) {
- completions.add('foobar');
- }
- if ('gondola'.startsWith(lastWord)) {
- completions.add('gondola');
- }
-
- return completions;
-}
-
-
-int _helpCount = 0;
-Commando cmdo;
-
-
-void _handleCommand(String rawCommand) {
- String command = rawCommand.trim();
- cmdo.hide();
- if (command == 'quit') {
- cmdo.close().then((_) {
- print('Exiting');
- });
- } else if (command == 'help') {
- switch (_helpCount) {
- case 0:
- print('I will not help you.');
- break;
- case 1:
- print('I mean it.');
- break;
- case 2:
- print('Seriously.');
- break;
- case 100:
- print('Well now.');
- break;
- default:
- print("Okay. Type 'quit' to quit");
- break;
- }
- _helpCount++;
- } else if (command == 'happyface') {
- print(':-)');
- } else {
- print('Received command($command)');
- }
- cmdo.show();
-}
-
-
-void main() {
- print('[Commando demo]');
- cmdo = new Commando(completer:_myCompleter);
- cmdo.commands.listen(_handleCommand);
-}
diff --git a/tools/ddbg/lib/terminfo.dart b/tools/ddbg/lib/terminfo.dart
deleted file mode 100644
index 4521031..0000000
--- a/tools/ddbg/lib/terminfo.dart
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:convert';
-import 'dart:io';
-
-int _tputGetInteger(String capName) {
- var result = Process.runSync('tput', ['$capName'], stdoutEncoding:UTF8);
- if (result.exitCode != 0) {
- return 0;
- }
- return int.parse(result.stdout);
-}
-
-String _tputGetSequence(String capName) {
- var result = Process.runSync('tput', ['$capName'], stdoutEncoding:UTF8);
- if (result.exitCode != 0) {
- return '';
- }
- return result.stdout;
-}
-
-class TermInfo {
- TermInfo() {
- resize();
- }
-
- int get lines => _lines;
- int get cols => _cols;
-
- int _lines;
- int _cols;
-
- void resize() {
- _lines = _tputGetInteger('lines');
- _cols = _tputGetInteger('cols');
- }
-
- // Back one character.
- final String cursorBack = _tputGetSequence('cub1');
-
- // Forward one character.
- final String cursorForward = _tputGetSequence('cuf1');
-
- // Up one character.
- final String cursorUp = _tputGetSequence('cuu1');
-
- // Down one character.
- final String cursorDown = _tputGetSequence('cud1');
-
- // Clear to end of line.
- final String clrEOL = _tputGetSequence('el');
-
- // Clear screen and home cursor.
- final String clear = _tputGetSequence('clear');
-}
diff --git a/tools/ddbg_service/HACKING.txt b/tools/ddbg_service/HACKING.txt
deleted file mode 100644
index 27c47d7..0000000
--- a/tools/ddbg_service/HACKING.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-ddbg_service
----
-
-ddbg_service is a command line debugger for the Dart VM implemented
-using the Dart VM Service. It is still being written and is not ready
-for use.
-
-Assumptions:
-You are running pub from the latest dev channel release of Dart Editor.
-
-Before running ddbg_service, you will need to run get packages from pub:
-
- pub upgrade
-
-Then launch ddbg_service:
-
- dart bin/ddbg_service.dart
diff --git a/tools/ddbg_service/bin/ddbg_service.dart b/tools/ddbg_service/bin/ddbg_service.dart
deleted file mode 100644
index 0023ba3..0000000
--- a/tools/ddbg_service/bin/ddbg_service.dart
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// A command line debugger implemented using the VM Service protocol.
-
-library ddbg2;
-
-import "dart:async";
-
-import 'package:ddbg/debugger.dart';
-
-Debugger debugger;
-
-void onError(self, parent, zone, error, StackTrace trace) {
- if (debugger != null) {
- debugger.onUncaughtError(error, trace);
- } else {
- print('\n--------\nExiting due to unexpected error:\n'
- ' $error\n$trace\n');
- exit();
- }
-}
-
-void main(List<String> args) {
- // Setup a zone which will exit the debugger cleanly on any uncaught
- // exception.
- var zone = Zone.ROOT.fork(specification:new ZoneSpecification(
- handleUncaughtError: onError));
-
- zone.run(() {
- debugger = new Debugger();
- });
-}
diff --git a/tools/ddbg_service/lib/commando.dart b/tools/ddbg_service/lib/commando.dart
deleted file mode 100644
index 3996880..0000000
--- a/tools/ddbg_service/lib/commando.dart
+++ /dev/null
@@ -1,750 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library commando;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-import 'package:ddbg/terminfo.dart';
-
-typedef List<String> CommandCompleter(List<String> commandParts);
-
-class Commando {
- // Ctrl keys
- static const runeCtrlA = 0x01;
- static const runeCtrlB = 0x02;
- static const runeCtrlD = 0x04;
- static const runeCtrlE = 0x05;
- static const runeCtrlF = 0x06;
- static const runeTAB = 0x09;
- static const runeNewline = 0x0a;
- static const runeCtrlK = 0x0b;
- static const runeCtrlL = 0x0c;
- static const runeCtrlN = 0x0e;
- static const runeCtrlP = 0x10;
- static const runeCtrlU = 0x15;
- static const runeCtrlY = 0x19;
- static const runeESC = 0x1b;
- static const runeSpace = 0x20;
- static const runeDEL = 0x7F;
-
- StreamController<String> _commandController;
-
- Stream get commands => _commandController.stream;
-
- Commando({consoleIn,
- consoleOut,
- this.prompt : '> ',
- this.completer : null}) {
- _stdin = (consoleIn != null ? consoleIn : stdin);
- _stdout = (consoleOut != null ? consoleOut : stdout);
- _commandController = new StreamController<String>(
- onCancel: _onCancel);
- _stdin.echoMode = false;
- _stdin.lineMode = false;
- _screenWidth = _term.cols - 1;
- _writePrompt();
- // TODO(turnidge): Handle errors in _stdin here.
- _stdinSubscription =
- _stdin.transform(UTF8.decoder).listen(_handleText, onDone:_done);
- }
-
- Future _onCancel() {
- _stdin.echoMode = true;
- _stdin.lineMode = true;
- var future = _stdinSubscription.cancel();
- if (future != null) {
- return future;
- } else {
- return new Future.value();
- }
- }
-
- // Before terminating, call close() to restore terminal settings.
- void _done() {
- _onCancel().then((_) {
- _commandController.close();
- });
- }
-
- void _handleText(String text) {
- try {
- if (!_promptShown) {
- _bufferedInput.write(text);
- return;
- }
-
- var runes = text.runes.toList();
- var pos = 0;
- while (pos < runes.length) {
- if (!_promptShown) {
- // A command was processed which hid the prompt. Buffer
- // the rest of the input.
- //
- // TODO(turnidge): Here and elsewhere in the file I pass
- // runes to String.fromCharCodes. Does this work?
- _bufferedInput.write(
- new String.fromCharCodes(runes.skip(pos)));
- return;
- }
-
- var rune = runes[pos];
-
- // Count consecutive tabs because double-tab is meaningful.
- if (rune == runeTAB) {
- _tabCount++;
- } else {
- _tabCount = 0;
- }
-
- if (_isControlRune(rune)) {
- pos += _handleControlSequence(runes, pos);
- } else {
- pos += _handleRegularSequence(runes, pos);
- }
- }
- } catch(e, trace) {
- _commandController.addError(e, trace);
- }
- }
-
- int _handleControlSequence(List<int> runes, int pos) {
- var runesConsumed = 1; // Most common result.
- var char = runes[pos];
- switch (char) {
- case runeCtrlA:
- _home();
- break;
-
- case runeCtrlB:
- _leftArrow();
- break;
-
- case runeCtrlD:
- if (_currentLine.length == 0) {
- // ^D on an empty line means quit.
- _stdout.writeln("^D");
- _done();
- } else {
- _delete();
- }
- break;
-
- case runeCtrlE:
- _end();
- break;
-
- case runeCtrlF:
- _rightArrow();
- break;
-
- case runeTAB:
- _complete(_tabCount > 1);
- break;
-
- case runeNewline:
- _newline();
- break;
-
- case runeCtrlK:
- _kill();
- break;
-
- case runeCtrlL:
- _clearScreen();
- break;
-
- case runeCtrlN:
- _historyNext();
- break;
-
- case runeCtrlP:
- _historyPrevious();
- break;
-
- case runeCtrlU:
- _clearLine();
- break;
-
- case runeCtrlY:
- _yank();
- break;
-
- case runeESC:
- // Check to see if this is an arrow key.
- if (pos + 2 < runes.length && // must be a 3 char sequence.
- runes[pos + 1] == 0x5b) { // second char must be '['.
- switch (runes[pos + 2]) {
- case 0x41: // ^[[A = up arrow
- _historyPrevious();
- runesConsumed = 3;
- break;
-
- case 0x42: // ^[[B = down arrow
- _historyNext();
- runesConsumed = 3;
- break;
-
- case 0x43: // ^[[C = right arrow
- _rightArrow();
- runesConsumed = 3;
- break;
-
- case 0x44: // ^[[D = left arrow
- _leftArrow();
- runesConsumed = 3;
- break;
-
- default:
- // Ignore the escape character.
- break;
- }
- }
- break;
-
- case runeDEL:
- _backspace();
- break;
-
- default:
- // Ignore the escape character.
- break;
- }
- return runesConsumed;
- }
-
- int _handleRegularSequence(List<int> runes, int pos) {
- var len = pos + 1;
- while (len < runes.length && !_isControlRune(runes[len])) {
- len++;
- }
- _addChars(runes.getRange(pos, len));
- return len;
- }
-
- bool _isControlRune(int char) {
- return (char >= 0x00 && char < 0x20) || (char == 0x7f);
- }
-
- void _writePromptAndLine() {
- _writePrompt();
- var pos = _writeRange(_currentLine, 0, _currentLine.length);
- _cursorPos = _move(pos, _cursorPos);
- }
-
- void _writePrompt() {
- _stdout.write(prompt);
- }
-
- void _addChars(Iterable<int> chars) {
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(chars)
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos + chars.length));
- }
-
- void _backspace() {
- if (_cursorPos == 0) {
- return;
- }
-
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos - 1))
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos - 1));
- }
-
- void _delete() {
- if (_cursorPos == _currentLine.length) {
- return;
- }
-
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(_currentLine.skip(_cursorPos + 1));
- _update(newLine, _cursorPos);
- }
-
- void _home() {
- _updatePos(0);
- }
-
- void _end() {
- _updatePos(_currentLine.length);
- }
-
- void _clearScreen() {
- _stdout.write(_term.clear);
- _term.resize();
- _screenWidth = _term.cols - 1;
- _writePromptAndLine();
- }
-
- void _kill() {
- var newLine = [];
- newLine.addAll(_currentLine.take(_cursorPos));
- _killBuffer = _currentLine.skip(_cursorPos).toList();
- _update(newLine, _cursorPos);
- }
-
- void _clearLine() {
- _update([], 0);
- }
-
- void _yank() {
- var newLine = [];
- newLine..addAll(_currentLine.take(_cursorPos))
- ..addAll(_killBuffer)
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, (_cursorPos + _killBuffer.length));
- }
-
- static String _trimLeadingSpaces(String line) {
- bool _isSpace(int rune) {
- return rune == runeSpace;
- }
- return new String.fromCharCodes(line.runes.skipWhile(_isSpace));
- }
-
- static String _sharedPrefix(String one, String two) {
- var len = min(one.length, two.length);
- var runesOne = one.runes.toList();
- var runesTwo = two.runes.toList();
- var pos;
- for (pos = 0; pos < len; pos++) {
- if (runesOne[pos] != runesTwo[pos]) {
- break;
- }
- }
- var shared = new String.fromCharCodes(runesOne.take(pos));
- return shared;
- }
-
- void _complete(bool showCompletions) {
- if (completer == null) {
- return;
- }
-
- var linePrefix = _currentLine.take(_cursorPos).toList();
- var lineAsString = new String.fromCharCodes(linePrefix);
- var commandParts = new List.from(lineAsString.split(' ').where((line) {
- return line != ' ' && line != '';
- }));
- if (lineAsString.endsWith(' ')) {
- // If the current line ends with a space, they are hoping to
- // complete the next word in the command. Add an empty string
- // to the commandParts to signal this to the completer.
- commandParts.add('');
- }
- List<String> completionList = completer(commandParts);
- var completion = null;
-
- if (completionList.length == 0) {
- // The current line admits no possible completion.
- return;
-
- } else if (completionList.length == 1) {
- // There is a single, non-ambiguous completion for the current line.
- completion = completionList[0];
-
- } else {
- // There are ambiguous completions. Find the longest common
- // shared prefix of all of the completions.
- completion = completionList.fold(completionList[0], _sharedPrefix);
- }
-
- if (showCompletions) {
- // User hit double-TAB. Show them all possible completions.
- completionList.sort((a,b) => a.compareTo(b));
- _move(_cursorPos, _currentLine.length);
- _stdout.writeln();
- _stdout.writeln(completionList);
- _writePromptAndLine();
- return;
-
- } else {
- // Apply the current completion.
- var completionRunes = completion.runes.toList();
-
- var newLine = [];
- newLine..addAll(completionRunes)
- ..addAll(_currentLine.skip(_cursorPos));
- _update(newLine, completionRunes.length);
- return;
- }
- }
-
- void _newline() {
- _addLineToHistory(_currentLine);
- _linePos = _lines.length;
-
- _end();
- _stdout.writeln();
-
- // Call the user's command handler.
- _commandController.add(new String.fromCharCodes(_currentLine));
-
- _currentLine = [];
- _cursorPos = 0;
- if (_promptShown) {
- _writePrompt();
- }
- }
-
- void _leftArrow() {
- _updatePos(_cursorPos - 1);
- }
-
- void _rightArrow() {
- _updatePos(_cursorPos + 1);
- }
-
- void _addLineToHistory(List<int> line) {
- if (_tempLineAdded) {
- _lines.removeLast();
- _tempLineAdded = false;
- }
- if (line.length > 0) {
- _lines.add(line);
- }
- }
-
- void _addTempLineToHistory(List<int> line) {
- _lines.add(line);
- _tempLineAdded = true;
- }
-
- void _replaceHistory(List<int> line, int linePos) {
- _lines[linePos] = line;
- }
-
- void _historyPrevious() {
- if (_linePos == 0) {
- return;
- }
-
- if (_linePos == _lines.length) {
- // The current in-progress line gets temporarily stored in history.
- _addTempLineToHistory(_currentLine);
- } else {
- // Any edits get committed to history.
- _replaceHistory(_currentLine, _linePos);
- }
-
- _linePos -= 1;
- var line = _lines[_linePos];
- _update(line, line.length);
- }
-
- void _historyNext() {
- // For the very first command, _linePos (0) will exceed
- // (_lines.length - 1) (-1) so we use a ">=" here instead of an "==".
- if (_linePos >= (_lines.length - 1)) {
- return;
- }
-
- // Any edits get committed to history.
- _replaceHistory(_currentLine, _linePos);
-
- _linePos += 1;
- var line = _lines[_linePos];
- _update(line, line.length);
- }
-
- void _updatePos(int newCursorPos) {
- if (newCursorPos < 0) {
- return;
- }
- if (newCursorPos > _currentLine.length) {
- return;
- }
-
- _cursorPos = _move(_cursorPos, newCursorPos);
- }
-
- void _update(List<int> newLine, int newCursorPos) {
- var pos = _cursorPos;
- var diffPos;
- var sharedLen = min(_currentLine.length, newLine.length);
-
- // Find first difference.
- for (diffPos = 0; diffPos < sharedLen; diffPos++) {
- if (_currentLine[diffPos] != newLine[diffPos]) {
- break;
- }
- }
-
- // Move the cursor to where the difference begins.
- pos = _move(pos, diffPos);
-
- // Write the new text.
- pos = _writeRange(newLine, pos, newLine.length);
-
- // Clear any extra characters at the end.
- pos = _clearRange(pos, _currentLine.length);
-
- // Move the cursor back to the input point.
- _cursorPos = _move(pos, newCursorPos);
- _currentLine = newLine;
- }
-
- void print(String text) {
- bool togglePrompt = _promptShown;
- if (togglePrompt) {
- hide();
- }
- _stdout.writeln(text);
- if (togglePrompt) {
- show();
- }
- }
-
- void hide() {
- if (!_promptShown) {
- return;
- }
- _promptShown = false;
- // We need to erase everything, including the prompt.
- var curLine = _getLine(_cursorPos);
- var lastLine = _getLine(_currentLine.length);
-
- // Go to last line.
- if (curLine < lastLine) {
- for (var i = 0; i < (lastLine - curLine); i++) {
- // This moves us to column 0.
- _stdout.write(_term.cursorDown);
- }
- curLine = lastLine;
- } else {
- // Move to column 0.
- _stdout.write('\r');
- }
-
- // Work our way up, clearing lines.
- while (true) {
- _stdout.write(_term.clrEOL);
- if (curLine > 0) {
- _stdout.write(_term.cursorUp);
- } else {
- break;
- }
- }
- }
-
- void show() {
- if (_promptShown) {
- return;
- }
- _promptShown = true;
- _writePromptAndLine();
-
- // If input was buffered while the prompt was hidden, process it
- // now.
- if (!_bufferedInput.isEmpty) {
- var input = _bufferedInput.toString();
- _bufferedInput.clear();
- _handleText(input);
- }
- }
-
- int _writeRange(List<int> text, int pos, int writeToPos) {
- if (pos >= writeToPos) {
- return pos;
- }
- while (pos < writeToPos) {
- var margin = _nextMargin(pos);
- var limit = min(writeToPos, margin);
- _stdout.write(new String.fromCharCodes(text.getRange(pos, limit)));
- pos = limit;
- if (pos == margin) {
- _stdout.write('\n');
- }
- }
- return pos;
- }
-
- int _clearRange(int pos, int clearToPos) {
- if (pos >= clearToPos) {
- return pos;
- }
- while (true) {
- var limit = _nextMargin(pos);
- _stdout.write(_term.clrEOL);
- if (limit >= clearToPos) {
- return pos;
- }
- _stdout.write('\n');
- pos = limit;
- }
- }
-
- int _move(int pos, int newPos) {
- if (pos == newPos) {
- return pos;
- }
-
- var curCol = _getCol(pos);
- var curLine = _getLine(pos);
- var newCol = _getCol(newPos);
- var newLine = _getLine(newPos);
-
- if (curLine > newLine) {
- for (var i = 0; i < (curLine - newLine); i++) {
- _stdout.write(_term.cursorUp);
- }
- }
- if (curLine < newLine) {
- for (var i = 0; i < (newLine - curLine); i++) {
- _stdout.write(_term.cursorDown);
- }
-
- // Moving down resets column to zero, oddly.
- curCol = 0;
- }
- if (curCol > newCol) {
- for (var i = 0; i < (curCol - newCol); i++) {
- _stdout.write(_term.cursorBack);
- }
- }
- if (curCol < newCol) {
- for (var i = 0; i < (newCol - curCol); i++) {
- _stdout.write(_term.cursorForward);
- }
- }
-
- return newPos;
- }
-
- int _nextMargin(int pos) {
- var truePos = pos + prompt.length;
- return ((truePos ~/ _screenWidth) + 1) * _screenWidth - prompt.length;
- }
-
- int _getLine(int pos) {
- var truePos = pos + prompt.length;
- return truePos ~/ _screenWidth;
- }
-
- int _getCol(int pos) {
- var truePos = pos + prompt.length;
- return truePos % _screenWidth;
- }
-
- Stdin _stdin;
- StreamSubscription _stdinSubscription;
- IOSink _stdout;
- final String prompt;
- bool _promptShown = true;
- final CommandCompleter completer;
- TermInfo _term = new TermInfo();
-
- // TODO(turnidge): See if we can get screen resize events.
- int _screenWidth;
- List<int> _currentLine = []; // A list of runes.
- StringBuffer _bufferedInput = new StringBuffer();
- List<List<int>> _lines = [];
-
- // When using the command history, the current line is temporarily
- // added to the history to allow the user to return to it. This
- // values tracks whether the history has a temporary line at the end.
- bool _tempLineAdded = false;
- int _linePos = 0;
- int _cursorPos = 0;
- int _tabCount = 0;
- List<int> _killBuffer = [];
-}
-
-
-// Demo code.
-
-
-List<String> _myCompleter(List<String> commandTokens) {
- List<String> completions = new List<String>();
-
- // First word completions.
- if (commandTokens.length <= 1) {
- String prefix = '';
- if (commandTokens.length == 1) {
- prefix = commandTokens.first;
- }
- if ('quit'.startsWith(prefix)) {
- completions.add('quit');
- }
- if ('help'.startsWith(prefix)) {
- completions.add('help');
- }
- if ('happyface'.startsWith(prefix)) {
- completions.add('happyface');
- }
- }
-
- // Complete 'foobar' or 'gondola' anywhere in string.
- String lastWord = commandTokens.last;
- if ('foobar'.startsWith(lastWord)) {
- completions.add('foobar');
- }
- if ('gondola'.startsWith(lastWord)) {
- completions.add('gondola');
- }
-
- return completions;
-}
-
-
-int _helpCount = 0;
-Commando cmdo;
-var cmdoSubscription;
-
-
-void _handleCommand(String rawCommand) {
- String command = rawCommand.trim();
- cmdo.hide();
- if (command == 'quit') {
- var future = cmdoSubscription.cancel();
- if (future != null) {
- future.then((_) {
- print('Exiting');
- exit(0);
- });
- } else {
- print('Exiting');
- exit(0);
- }
- } else if (command == 'help') {
- switch (_helpCount) {
- case 0:
- print('I will not help you.');
- break;
- case 1:
- print('I mean it.');
- break;
- case 2:
- print('Seriously.');
- break;
- case 100:
- print('Well now.');
- break;
- default:
- print("Okay. Type 'quit' to quit");
- break;
- }
- _helpCount++;
- } else if (command == 'happyface') {
- print(':-)');
- } else {
- print('Received command($command)');
- }
- cmdo.show();
-}
-
-
-void main() {
- print('[Commando demo]');
- cmdo = new Commando(completer:_myCompleter);
- cmdoSubscription = cmdo.commands.listen(_handleCommand);
-}
diff --git a/tools/ddbg_service/lib/debugger.dart b/tools/ddbg_service/lib/debugger.dart
deleted file mode 100644
index 0a04161..0000000
--- a/tools/ddbg_service/lib/debugger.dart
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library debugger;
-
-import "dart:async";
-import "dart:io";
-
-import "package:ddbg/commando.dart";
-import "package:observatory/service_io.dart";
-
-class Debugger {
- Commando cmdo;
- var _cmdoSubscription;
-
- CommandList _commands;
-
- VM _vm;
- VM get vm => _vm;
- set vm(VM vm) {
- if (_vm == vm) {
- // Do nothing.
- return;
- }
- if (_vm != null) {
- _vm.disconnect();
- }
- if (vm != null) {
- vm.onConnect.then(_vmConnected);
- vm.onDisconnect.then(_vmDisconnected);
- vm.errors.stream.listen(_onServiceError);
- vm.exceptions.stream.listen(_onServiceException);
- vm.events.stream.listen(_onServiceEvent);
- }
- _vm = vm;
- }
-
- _vmConnected(VM vm) {
- cmdo.print('Connected to vm');
- }
-
- _vmDisconnected(VM vm) {
- cmdo.print('Disconnected from vm');
- }
-
- _onServiceError(ServiceError error) {
- cmdo.print('error $error');
- }
-
- _onServiceException(ServiceException exception) {
- cmdo.print('${exception.message}');
- }
-
- _onServiceEvent(ServiceEvent event) {
- switch (event.eventType) {
- case 'GC':
- // Ignore GC events for now.
- break;
- default:
- cmdo.print('event $event');
- break;
- }
- }
-
- VM _isolate;
- VM get isolate => _isolate;
- set isolate(Isolate isolate) {
- _isolate = isolate;
- cmdo.print('Current isolate is now isolate ${getIsolateIndex(_isolate)}');
- }
-
- Map _isolateIndexMap = new Map();
- int _nextIsolateIndex = 0;
- int getIsolateIndex(Isolate isolate) {
- var index = _isolateIndexMap[isolate.id];
- if (index == null) {
- index = _nextIsolateIndex++;
- _isolateIndexMap[isolate.id] = index;
- }
- return index;
- }
-
- void onUncaughtError(error, StackTrace trace) {
- if (error is ServiceException ||
- error is ServiceError) {
- // These are handled elsewhere. Ignore.
- return;
- }
- cmdo.print('\n--------\nExiting due to unexpected error:\n'
- ' $error\n$trace\n');
- quit();
- }
-
- Debugger() {
- cmdo = new Commando(completer: _completeCommand);
- _cmdoSubscription = cmdo.commands.listen(_processCommand,
- onError: _cmdoError,
- onDone: _cmdoDone);
- _commands = new CommandList();
- _commands.register(new AttachCommand());
- _commands.register(new DetachCommand());
- _commands.register(new HelpCommand(_commands));
- _commands.register(new IsolateCommand());
- _commands.register(new QuitCommand());
- }
-
- Future _closeCmdo() {
- var sub = _cmdoSubscription;
- _cmdoSubscription = null;
- cmdo = null;
-
- var future = sub.cancel();
- if (future != null) {
- return future;
- } else {
- return new Future.value();
- }
- }
-
- Future quit() {
- return Future.wait([_closeCmdo()]).then((_) {
- exit(0);
- });
- }
-
- void _cmdoError(error, StackTrace trace) {
- cmdo.print('\n--------\nExiting due to unexpected error:\n'
- ' $error\n$trace\n');
- quit();
- }
-
- void _cmdoDone() {
- quit();
- }
-
- List<String> _completeCommand(List<String> commandParts) {
- return _commands.complete(commandParts);
- }
-
- void _processCommand(String cmdLine) {
- void huh() {
- cmdo.print("'$cmdLine' not understood, try 'help' for help.");
- }
-
- cmdo.hide();
- cmdLine = cmdLine.trim();
- var args = cmdLine.split(' ');
- if (args.length == 0) {
- return;
- }
- var command = args[0];
- var matches = _commands.match(command, true);
- if (matches.length == 0) {
- huh();
- cmdo.show();
- } else if (matches.length == 1) {
- matches[0].run(this, args).then((_) {
- cmdo.show();
- });
- } else {
- var matchNames = matches.map((handler) => handler.name);
- cmdo.print("Ambiguous command '$command' : ${matchNames.toList()}");
- cmdo.show();
- }
- }
-
-}
-
-// Every debugger command extends this base class.
-abstract class Command {
- String get name;
- String get helpShort;
- void printHelp(Debugger debugger, List<String> args);
- Future run(Debugger debugger, List<String> args);
- List<String> complete(List<String> commandParts) {
- return ["$name ${commandParts.join(' ')}"];
-
- }
-}
-
-class AttachCommand extends Command {
- final name = 'attach';
- final helpShort = 'Attach to a running Dart VM';
- void printHelp(Debugger debugger, List<String> args) {
- debugger.cmdo.print('''
------ attach -----
-
-Attach to the Dart VM running at the indicated host:port. If no
-host:port is provided, attach to the VM running on the default port.
-
-Usage:
- attach
- attach <host:port>
-''');
- }
-
- Future run(Debugger debugger, List<String> args) {
- var cmdo = debugger.cmdo;
- if (args.length > 2) {
- cmdo.print('$name expects 0 or 1 arguments');
- return new Future.value();
- }
- String hostPort = 'localhost:8181';
- if (args.length > 1) {
- hostPort = args[1];
- }
-
- debugger.vm = new WebSocketVM(new WebSocketVMTarget('ws://${hostPort}/ws'));
- return debugger.vm.load().then((vm) {
- if (debugger.isolate == null) {
- for (var isolate in vm.isolates) {
- if (isolate.name == 'root') {
- debugger.isolate = isolate;
- }
- }
- }
- });
- }
-}
-
-class CommandList {
- List _commands = new List<Command>();
-
- void register(Command cmd) {
- _commands.add(cmd);
- }
-
- List<Command> match(String commandName, bool exactMatchWins) {
- var matches = [];
- for (var command in _commands) {
- if (command.name.startsWith(commandName)) {
- if (exactMatchWins && command.name == commandName) {
- // Exact match
- return [command];
- } else {
- matches.add(command);
- }
- }
- }
- return matches;
- }
-
- List<String> complete(List<String> commandParts) {
- var completions = new List<String>();
- String prefix = commandParts[0];
- for (var command in _commands) {
- if (command.name.startsWith(prefix)) {
- completions.addAll(command.complete(commandParts.sublist(1)));
- }
- }
- return completions;
- }
-
- void printHelp(Debugger debugger, List<String> args) {
- var cmdo = debugger.cmdo;
- if (args.length <= 1) {
- cmdo.print("\nDebugger commands:\n");
- for (var command in _commands) {
- cmdo.print(' ${command.name.padRight(11)} ${command.helpShort}');
- }
- cmdo.print("For more information about a particular command, type:\n\n"
- " help <command>\n");
-
- cmdo.print("Commands may be abbreviated: e.g. type 'h' for 'help.\n");
- } else {
- var commandName = args[1];
- var matches =match(commandName, true);
- if (matches.length == 0) {
- cmdo.print("Command '$commandName' not recognized. "
- "Try 'help' for a list of commands.");
- } else {
- for (var command in matches) {
- command.printHelp(debugger, args);
- }
- }
- }
- }
-}
-
-class DetachCommand extends Command {
- final name = 'detach';
- final helpShort = 'Detach from a running Dart VM';
- void printHelp(Debugger debugger, List<String> args) {
- debugger.cmdo.print('''
------ detach -----
-
-Detach from the Dart VM.
-
-Usage:
- detach
-''');
- }
-
- Future run(Debugger debugger, List<String> args) {
- var cmdo = debugger.cmdo;
- if (args.length > 1) {
- cmdo.print('$name expects no arguments');
- return new Future.value();
- }
- if (debugger.vm == null) {
- cmdo.print('No VM is attached');
- } else {
- debugger.vm = null;
- }
- return new Future.value();
- }
-}
-
-class HelpCommand extends Command {
- HelpCommand(this._commands);
- final CommandList _commands;
-
- final name = 'help';
- final helpShort = 'Show a list of debugger commands';
- void printHelp(Debugger debugger, List<String> args) {
- debugger.cmdo.print('''
------ help -----
-
-Show a list of debugger commands or get more information about a
-particular command.
-
-Usage:
- help
- help <command>
-''');
- }
-
- Future run(Debugger debugger, List<String> args) {
- _commands.printHelp(debugger, args);
- return new Future.value();
- }
-
- List<String> complete(List<String> commandParts) {
- if (commandParts.isEmpty) {
- return ['$name '];
- }
- return _commands.complete(commandParts).map((value) {
- return '$name $value';
- });
- }
-}
-
-class IsolateCommand extends Command {
- final name = 'isolate';
- final helpShort = 'Isolate control';
- void printHelp(Debugger debugger, List<String> args) {
- debugger.cmdo.print('''
------ isolate -----
-
-List all isolates.
-
-Usage:
- isolate
- isolate list
-
-Set current isolate.
-
-Usage:
- isolate <id>
-''');
- }
-
- Future run(Debugger debugger, List<String> args) {
- var cmdo = debugger.cmdo;
- if (args.length == 1 ||
- (args.length == 2 && args[1] == 'list')) {
- return _listIsolates(debugger);
- } else if (args.length == 2) {
- cmdo.print('UNIMPLEMENTED');
- return new Future.value();
- } else {
- if (args.length > 1) {
- cmdo.print('Unrecognized isolate command');
- printHelp(debugger, []);
- return new Future.value();
- }
- }
- }
-
- Future _listIsolates(Debugger debugger) {
- var cmdo = debugger.cmdo;
- if (debugger.vm == null) {
- cmdo.print('No VM is attached');
- return new Future.value();
- }
- return debugger.vm.reload().then((vm) {
- // Sort the isolates by their indices.
- var isolates = vm.isolates.toList();
- isolates.sort((iso1, iso2) {
- return (debugger.getIsolateIndex(iso1) -
- debugger.getIsolateIndex(iso2));
- });
-
- StringBuffer sb = new StringBuffer();
- cmdo.print(' ID NAME STATE');
- cmdo.print('-----------------------------------------------');
- for (var isolate in isolates) {
- if (isolate == debugger.isolate) {
- sb.write('* ');
- } else {
- sb.write(' ');
- }
- sb.write(debugger.getIsolateIndex(isolate).toString().padRight(8));
- sb.write(' ');
- sb.write(isolate.name.padRight(12));
- sb.write(' ');
- if (isolate.pauseEvent != null) {
- switch (isolate.pauseEvent.eventType) {
- case 'IsolateCreated':
- sb.write('paused at isolate start');
- break;
- case 'IsolateShutdown':
- sb.write('paused at isolate exit');
- break;
- case 'IsolateInterrupted':
- sb.write('paused');
- break;
- case 'BreakpointReached':
- sb.write('paused by breakpoint');
- break;
- case 'ExceptionThrown':
- sb.write('paused by exception');
- break;
- default:
- sb.write('paused by unknown cause');
- break;
- }
- } else if (isolate.running) {
- sb.write('running');
- } else if (isolate.idle) {
- sb.write('idle');
- } else if (isolate.loading) {
- // TODO(turnidge): This is weird in a command line debugger.
- sb.write('(not available)');
- }
- sb.write('\n');
- }
- cmdo.print(sb);
- });
- return new Future.value();
- }
-
- List<String> complete(List<String> commandParts) {
- if (commandParts.isEmpty) {
- return ['$name ${commandParts.join(" ")}'];
- } else {
- var completions = _commands.complete(commandParts);
- return completions.map((completion) {
- return '$name $completion';
- });
- }
- }
-}
-
-class QuitCommand extends Command {
- final name = 'quit';
- final helpShort = 'Quit the debugger.';
- void printHelp(Debugger debugger, List<String> args) {
- debugger.cmdo.print('''
------ quit -----
-
-Quit the debugger.
-
-Usage:
- quit
-''');
- }
-
- Future run(Debugger debugger, List<String> args) {
- var cmdo = debugger.cmdo;
- if (args.length > 1) {
- cmdo.print("Unexpected arguments to $name command.");
- return new Future.value();
- }
- return debugger.quit();
- }
-}
diff --git a/tools/ddbg_service/lib/terminfo.dart b/tools/ddbg_service/lib/terminfo.dart
deleted file mode 100644
index 0ec8860..0000000
--- a/tools/ddbg_service/lib/terminfo.dart
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library terminfo;
-
-import 'dart:convert';
-import 'dart:io';
-
-int _tputGetInteger(String capName) {
- var result = Process.runSync('tput', ['$capName'], stdoutEncoding:UTF8);
- if (result.exitCode != 0) {
- return 0;
- }
- return int.parse(result.stdout);
-}
-
-String _tputGetSequence(String capName) {
- var result = Process.runSync('tput', ['$capName'], stdoutEncoding:UTF8);
- if (result.exitCode != 0) {
- return '';
- }
- return result.stdout;
-}
-
-class TermInfo {
- TermInfo() {
- resize();
- }
-
- int get lines => _lines;
- int get cols => _cols;
-
- int _lines;
- int _cols;
-
- void resize() {
- _lines = _tputGetInteger('lines');
- _cols = _tputGetInteger('cols');
- }
-
- // Back one character.
- final String cursorBack = _tputGetSequence('cub1');
-
- // Forward one character.
- final String cursorForward = _tputGetSequence('cuf1');
-
- // Up one character.
- final String cursorUp = _tputGetSequence('cuu1');
-
- // Down one character.
- final String cursorDown = _tputGetSequence('cud1');
-
- // Clear to end of line.
- final String clrEOL = _tputGetSequence('el');
-
- // Clear screen and home cursor.
- final String clear = _tputGetSequence('clear');
-}
diff --git a/tools/ddbg_service/pubspec.yaml b/tools/ddbg_service/pubspec.yaml
deleted file mode 100644
index f6b93de..0000000
--- a/tools/ddbg_service/pubspec.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-name: ddbg
-description: A command-line Dart debugger
-dependencies:
- logging: any
- observatory:
- path: /Users/turnidge/ws/dart-repo/dart/runtime/bin/vmservice/observatory
-#dev_dependencies:
-# unittest: any
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index 25978fa..fb3f166 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -14,7 +14,7 @@
"dartium_chromium_commit": "62a7524d4f71c9e0858d24b0aa1bbff3a2d09bff",
"chromium_base_revision": "297060",
"dartium_webkit_branch": "/blink/branches/dart/dartium",
- "dartium_webkit_revision": "202699",
+ "dartium_webkit_revision": "202728",
# We use mirrors of all github repos to guarantee reproducibility and
# consistency between what users see and what the bots see.
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 0f8867d..92a5ed0 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -722,6 +722,9 @@
# postMessage
'any set MessagePort.postMessage': _serialize_SSV,
'SerializedScriptValue set Window.postMessage': _serialize_SSV,
+ 'SerializedScriptValue set Worker.postMessage': _serialize_SSV,
+ 'any set DedicatedWorkerGlobalScope.postMessage' : _serialize_SSV,
+ 'SerializedScriptValue set ServiceWorkerClient.postMessage': _serialize_SSV,
'* get CustomEvent.detail':
Conversion('convertNativeToDart_SerializedScriptValue',
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index e207e79..78193a5 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -439,12 +439,6 @@
'DataTransferItemList.add(DOMString data, DOMString type)': 'addData',
'FormData.append(DOMString name, Blob value, DOMString filename)':
'appendBlob',
- 'IDBDatabase.transaction(DOMStringList storeNames, IDBTransactionMode mode)':
- 'transactionStores',
- 'IDBDatabase.transaction(sequence<DOMString> storeNames, IDBTransactionMode mode)':
- 'transactionList',
- 'IDBDatabase.transaction(DOMString storeName, IDBTransactionMode mode)':
- 'transactionStore',
'RTCDataChannel.send(ArrayBuffer data)': 'sendByteBuffer',
'RTCDataChannel.send(ArrayBufferView data)': 'sendTypedData',
'RTCDataChannel.send(Blob data)': 'sendBlob',
@@ -777,6 +771,7 @@
'HTMLTitleElement.text',
'HTMLUListElement.compact',
'HTMLUListElement.type',
+ 'IDBDatabase.transaction', # We do this in a template without the generated implementation at all.
'Location.valueOf',
'MessageEvent.ports',
'MessageEvent.webkitInitMessageEvent',
diff --git a/tools/dom/templates/html/impl/impl_Document.darttemplate b/tools/dom/templates/html/impl/impl_Document.darttemplate
index 2060813..ca0705a 100644
--- a/tools/dom/templates/html/impl/impl_Document.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Document.darttemplate
@@ -64,11 +64,9 @@
@DomName('Document.createElement')
Element createElement(String tagName, [String typeExtension]) {
$if DART2JS
- if (typeExtension == null) {
- return _createElement_2(tagName);
- } else {
- return _createElement(tagName, typeExtension);
- }
+ return (typeExtension == null)
+ ? _createElement_2(tagName)
+ : _createElement(tagName, typeExtension);
$else
var newElement = (typeExtension == null) ?
_blink.BlinkDocument.instance.createElement_Callback_1_(unwrap_jso(this), tagName) :
@@ -94,24 +92,23 @@
// The two-argument version of this is automatically generated, but we need to
// omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
@DomName('Document.createElement')
- _createElement_2(String tagName) => JS('', '#.createElement(#)', this, tagName);
+ _createElement_2(String tagName) =>
+ JS('Element', '#.createElement(#)', this, tagName);
// The three-argument version of this is automatically generated, but we need to
// omit the typeExtension if it's null on Firefox or we get an is="null" attribute.
@DomName('Document.createElementNS')
_createElementNS_2(String namespaceURI, String qualifiedName) =>
- JS('', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
+ JS('Element', '#.createElementNS(#, #)', this, namespaceURI, qualifiedName);
$endif
@DomName('Document.createElementNS')
@DocsEditable()
Element createElementNS(String namespaceURI, String qualifiedName, [String typeExtension]) {
$if DART2JS
- if (typeExtension == null) {
- return _createElementNS_2(namespaceURI, qualifiedName);
- } else {
- return _createElementNS(namespaceURI, qualifiedName, typeExtension);
- }
+ return (typeExtension == null)
+ ? _createElementNS_2(namespaceURI, qualifiedName)
+ : _createElementNS(namespaceURI, qualifiedName, typeExtension);
$else
var newElement = (typeExtension == null) ?
_blink.BlinkDocument.instance.createElementNS_Callback_2_(unwrap_jso(this), namespaceURI, qualifiedName) :
diff --git a/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate b/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
index c89c29a..8a74ad3 100644
--- a/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBDatabase.darttemplate
@@ -53,7 +53,7 @@
List storeNames_1 = convertDartToNative_StringArray(storeNames);
return _transaction(storeNames_1, mode);
}
-
+
Transaction transactionStores(DomStringList storeNames, String mode) {
if (mode != 'readonly' && mode != 'readwrite') {
throw new ArgumentError(mode);
@@ -63,6 +63,28 @@
@JSName('transaction')
Transaction _transaction(stores, mode) native;
+$else
+ Transaction transaction(storeName_OR_storeNames, String mode) {
+ if (mode != 'readonly' && mode != 'readwrite') {
+ throw new ArgumentError("Invalid transaction mode $mode");
+ }
+ var names;
+ if (storeName_OR_storeNames == null) {
+ throw new ArgumentError("stores may not be null in transaction");
+ } else if (storeName_OR_storeNames is String || storeName_OR_storeNames is DomStringList) {
+ names = unwrap_jso(storeName_OR_storeNames);
+ } else if (storeName_OR_storeNames is List<String>) {
+ names = convertDartToNative_List(storeName_OR_storeNames);
+ } else {
+ throw new ArgumentError("Invalid store(s) $store_Name_OR_storeNames");
+ }
+
+ return wrap_jso(_blink.BlinkIDBDatabase.instance.transaction_Callback_2_(unwrap_jso(this), names, mode));
+ }
+
+ Transaction transactionList(List<String> storeNames, String mode) => transaction(storeNames, mode);
+ Transaction transactionStores(List<String> storeNames, String mode) => transaction(storeNames, mode);
+ Transaction transactionStore(String storeName, String mode) => transaction(storeName, mode);
$endif
$!MEMBERS}
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index 683ca51..ebaf935 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -29,9 +29,10 @@
# '-fvisibility=hidden',
# '-fvisibility-inlines-hidden',
'-fstack-protector',
+ '-Wa,--noexecstack',
],
'ldflags': [
- '-Wa,--noexecstack',
+ '-Wl,-z,noexecstack',
'-Wl,-z,now',
'-Wl,-z,relro',
],
@@ -236,6 +237,10 @@
],
'cflags': [
'-O3',
+ '-ffunction-sections',
+ ],
+ 'ldflags': [
+ '-Wl,--gc-sections',
],
},
},
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index 3f22df5..f709727 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -25,6 +25,7 @@
'GCC_ENABLE_CPP_RTTI': 'NO', # -fno-rtti
'GCC_DEBUGGING_SYMBOLS': 'default', # -g
'GCC_GENERATE_DEBUGGING_SYMBOLS': 'YES', # Do not strip symbols
+ 'DEAD_CODE_STRIPPING': 'YES', # -Wl,-dead_strip
'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
'GCC_INLINES_ARE_PRIVATE_EXTERN': 'YES', # -fvisibility-inlines-hidden
'GCC_WARN_NON_VIRTUAL_DESTRUCTOR': 'YES', # -Wnon-virtual-dtor
diff --git a/tools/make_links.py b/tools/make_links.py
index 58bc9cb..157008a 100644
--- a/tools/make_links.py
+++ b/tools/make_links.py
@@ -29,8 +29,9 @@
import utils
# Useful messages when we find orphaned checkouts.
-old_directories = {'package_config':
- 'Please remove third_party/pkg/package_config.'}
+old_directories = {
+ 'package_config': 'Please remove third_party/pkg/package_config.',
+ 'analyzer_cli': 'Please remove third_party/pkg/analyzer_cli.'}
def get_options():
result = optparse.OptionParser()
diff --git a/tools/precompilation/test_linux.sh b/tools/precompilation/test_linux.sh
index d6263b1..f5b1865 100755
--- a/tools/precompilation/test_linux.sh
+++ b/tools/precompilation/test_linux.sh
@@ -6,8 +6,8 @@
./tools/build.py -mdebug -ax64 runtime
-./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./out/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
gcc -m64 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart --run-precompiled-snapshot --observe --profile-vm not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_linux_simarm.sh b/tools/precompilation/test_linux_simarm.sh
index 5f477f6..f87c6a5 100755
--- a/tools/precompilation/test_linux_simarm.sh
+++ b/tools/precompilation/test_linux_simarm.sh
@@ -6,8 +6,8 @@
./tools/build.py -mdebug -asimarm runtime
-./out/DebugSIMARM/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./out/DebugSIMARM/dart_no_snapshot --gen-precompiled-snapshot --package-root=out/DebugX64/packages/ "$1"
gcc -m32 -shared -Wl,-soname,libprecompiled.so -o libprecompiled.so precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart --run-precompiled-snapshot --observe not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" gdb -ex run --args ./out/DebugSIMARM/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/tools/precompilation/test_macos.sh b/tools/precompilation/test_macos.sh
index 4dbf51c..510478f 100755
--- a/tools/precompilation/test_macos.sh
+++ b/tools/precompilation/test_macos.sh
@@ -6,8 +6,8 @@
./tools/build.py -mdebug -ax64 runtime
-./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot "$1"
+./xcodebuild/DebugX64/dart_no_snapshot --gen-precompiled-snapshot --package-root=xcodebuild/DebugX64/packages/ "$1"
clang -m64 -dynamiclib -o libprecompiled.dylib precompiled.S
-LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart --run-precompiled-snapshot --observe not_used.dart
+LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$PWD" lldb -- ./xcodebuild/DebugX64/dart_precompiled --run-precompiled-snapshot not_used.dart
diff --git a/utils/dartanalyzer/dartanalyzer.gyp b/utils/dartanalyzer/dartanalyzer.gyp
index 93dc15f..9617f05 100644
--- a/utils/dartanalyzer/dartanalyzer.gyp
+++ b/utils/dartanalyzer/dartanalyzer.gyp
@@ -18,7 +18,7 @@
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
'../../sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart',
'<(SHARED_INTERMEDIATE_DIR)/packages.stamp',
- '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../third_party/pkg/analyzer_cli"])',
+ '<!@(["python", "../../tools/list_files.py", "\\.dart$", "../../pkg/analyzer_cli"])',
],
'outputs': [
'<(SHARED_INTERMEDIATE_DIR)/dartanalyzer.dart.snapshot',
@@ -27,7 +27,7 @@
'<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
'--snapshot=<(SHARED_INTERMEDIATE_DIR)/dartanalyzer.dart.snapshot',
'--package-root=<(PRODUCT_DIR)/packages/',
- '../../third_party/pkg/analyzer_cli/bin/analyzer.dart',
+ '../../pkg/analyzer_cli/bin/analyzer.dart',
],
},
],