Version 1.14.0-dev.4.0
Merge commit '1ffc230bf0952850497c913fb878df4333290abf' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 087ba19..3172396 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,9 @@
* Added `Uri.data` getter for `data:` URIs, and `UriData` class for the
return type.
* Added `growable` parameter to `List.filled` constructor.
+ * Added microsecond support to `DateTime`: `DateTime.microsecond`,
+ `DateTime.microsecondsSinceEpoch`, and
+ `new DateTime.fromMicrosecondsSinceEpoch`.
* `dart:math`
* `Random` added a `secure` constructor returning a cryptographically secure
@@ -21,6 +24,12 @@
### Tool changes
+* `dartfmt`
+
+ * Better line splitting in a variety of cases.
+
+ * Other optimizations and bug fixes.
+
* Pub
* **Breaking:** Pub now eagerly emits an error when a pubspec's "name" field
diff --git a/DEPS b/DEPS
index 8f64f6c..ed1aa95 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
# Revisions of /third_party/* dependencies.
"7zip_rev" : "@19997",
"args_tag": "@0.13.0",
- "async_tag": "@1.2.0",
+ "async_tag": "@1.4.0",
"barback_tag" : "@0.15.2+7",
"boringssl_rev" : "@daeafc22c66ad48f6b32fc8d3362eb9ba31b774e",
"charcode_tag": "@1.1.0",
@@ -47,12 +47,13 @@
"clang_rev" : "@28450",
"cli_util_tag" : "@0.0.1+2",
"collection_rev": "@f6135e6350c63eb3f4dd12953b8d4363faff16fc",
+ "convert_tag": "@1.0.0",
"crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
"csslib_tag" : "@0.12.0",
"dart2js_info_rev" : "@0a221eaf16aec3879c45719de656680ccb80d8a1",
- "dartdoc_tag" : "@v0.8.3",
+ "dartdoc_tag" : "@v0.8.4",
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
- "dart_style_tag": "@0.2.0",
+ "dart_style_tag": "@0.2.2",
"dev_compiler_rev": "@0.1.9",
"fake_async_rev" : "@38614",
"firefox_jsshell_rev" : "@45554",
@@ -60,14 +61,14 @@
"gsutil_rev" : "@33376",
"html_tag" : "@0.12.1+1",
"http_rev" : "@9b93e1542c753090c50b46ef1592d44bc858bfe7",
- "http_multi_server_tag" : "@1.3.2",
- "http_parser_rev" : "@8b179e36aba985208e4c5fb15cfddd386b6370a4",
+ "http_multi_server_tag" : "@2.0.0",
+ "http_parser_tag" : "@1.1.0",
"http_throttle_rev" : "@a81f08be942cdd608883c7b67795c12226abc235",
"idl_parser_rev": "@6316d5982dc24b34d09dd8b10fbeaaff28d83a48",
- "intl_rev": "@32047558bd220a53c1f4d93a26d54b83533b1475",
+ "intl_rev": "@a8b480b9c436f6c0ec16730804c914bdb4e30d53",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@1.1.1",
- "linter_rev": "@e5281475126efdc556c3eba6a8b6683fd814b033",
+ "linter_rev": "@5a599fd32d3b6ef00ffa7c330d1f32bbad287228",
"logging_rev": "@85d83e002670545e9039ad3985f0018ab640e597",
"markdown_rev": "@4aaadf3d940bb172e1f6285af4d2b1710d309982",
"matcher_tag": "@0.12.0",
@@ -82,13 +83,13 @@
"petitparser_rev" : "@37878",
"ply_rev": "@604b32590ffad5cbb82e4afef1d305512d06ae93",
"plugin_tag": "@0.1.0",
- "pool_rev": "@e454b4b54d2987e8d2f0fbd3ac519641ada9bd0f",
- "pub_rev": "@8c091bf6332e8b392fdac63ae297426fb65ed925",
+ "pool_tag": "@1.2.1",
+ "pub_rev": "@3000544b752bbc89e5e01559eed7f70e9401632b",
"pub_cache_tag": "@v0.1.0",
"pub_semver_tag": "@1.2.1",
"quiver_tag": "@0.21.4",
"root_certificates_rev": "@c3a41df63afacec62fcb8135196177e35fe72f71",
- "scheduled_test_tag": "@0.12.1+2",
+ "scheduled_test_tag": "@0.12.4+2",
"shelf_tag": "@0.6.2+1",
"smoke_rev" : "@f3361191cc2a85ebc1e4d4c33aec672d7915aba9",
"source_maps_tag": "@0.10.1",
@@ -99,7 +100,7 @@
"stack_trace_tag": "@1.4.2",
"string_scanner_tag": "@0.1.4",
"sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
- "test_tag": "@0.12.3+8",
+ "test_tag": "@0.12.6+1",
"test_reflective_loader_tag": "@0.0.3",
"utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
"unittest_tag": "@0.11.6",
@@ -183,6 +184,8 @@
(Var("github_mirror") % "cli_util") + Var("cli_util_tag"),
Var("dart_root") + "/third_party/pkg/collection":
(Var("github_mirror") % "collection") + Var("collection_rev"),
+ Var("dart_root") + "/third_party/pkg/convert":
+ "https://github.com/dart-lang/convert.git" + Var("convert_tag"),
Var("dart_root") + "/third_party/pkg/crypto":
(Var("github_mirror") % "crypto") + Var("crypto_rev"),
Var("dart_root") + "/third_party/pkg/csslib":
@@ -205,7 +208,7 @@
(Var("github_mirror") % "http_multi_server") +
Var("http_multi_server_tag"),
Var("dart_root") + "/third_party/pkg/http_parser":
- (Var("github_mirror") % "http_parser") + Var("http_parser_rev"),
+ (Var("github_mirror") % "http_parser") + Var("http_parser_tag"),
Var("dart_root") + "/third_party/pkg/http_throttle":
(Var("github_mirror") % "http_throttle") +
Var("http_throttle_rev"),
@@ -244,7 +247,7 @@
Var("dart_root") + "/third_party/pkg/plugin":
(Var("github_mirror") % "plugin") + Var("plugin_tag"),
Var("dart_root") + "/third_party/pkg/pool":
- (Var("github_mirror") % "pool") + Var("pool_rev"),
+ (Var("github_mirror") % "pool") + Var("pool_tag"),
Var("dart_root") + "/third_party/pkg/pub_semver":
(Var("github_mirror") % "pub_semver") + Var("pub_semver_tag"),
Var("dart_root") + "/third_party/pkg/pub":
diff --git a/pkg/analysis_server/benchmark/integration/README.md b/pkg/analysis_server/benchmark/integration/README.md
index 78431f9..9955c11 100644
--- a/pkg/analysis_server/benchmark/integration/README.md
+++ b/pkg/analysis_server/benchmark/integration/README.md
@@ -20,9 +20,7 @@
* **inputFile** = the instrumentation or log file
Additional arguments are passed directly to main.dart.
-For example, you may want to specify --newTaskModel to measure performance
-with the new task model versus the old task model,
-or if the log was recorded on one machine and is played back on another,
+For example, if the log was recorded on one machine and is played back on another,
then you might need to specify -m<oldSrcPath>,<newSrcPath>
to map the source paths for playback.
When specifying additional arguments, any occurrences of @tmpSrcDir@
@@ -49,7 +47,6 @@
* **-t, --tmpSrcDir <dirPath>**
The temporary directory containing source used during performance measurement.
WARNING: The contents of the target directory will be modified
-* **--newTaskModel** enable the use of the new task model
* **-d, --diagnosticPort** localhost port on which server
will provide diagnostic web pages
* **-v, --verbose** Verbose logging
diff --git a/pkg/analysis_server/benchmark/integration/driver.dart b/pkg/analysis_server/benchmark/integration/driver.dart
index 80aec4c1..aac45a2 100644
--- a/pkg/analysis_server/benchmark/integration/driver.dart
+++ b/pkg/analysis_server/benchmark/integration/driver.dart
@@ -45,8 +45,6 @@
final Logger logger = new Logger('Driver');
- final bool newTaskModel;
-
/**
* The diagnostic port for Analysis Server or `null` if none.
*/
@@ -70,7 +68,7 @@
*/
Completer<Results> _runCompleter = new Completer<Results>();
- Driver({this.newTaskModel, this.diagnosticPort});
+ Driver({this.diagnosticPort});
/**
* Return a [Future] that completes with the [Results] of running
@@ -114,9 +112,7 @@
});
running = true;
return server
- .start(
- diagnosticPort: diagnosticPort,
- newTaskModel: newTaskModel /*profileServer: true*/)
+ .start(diagnosticPort: diagnosticPort /*profileServer: true*/)
.then((params) {
server.listenToOutput(dispatchNotification);
server.exitCode.then((_) {
diff --git a/pkg/analysis_server/benchmark/integration/main.dart b/pkg/analysis_server/benchmark/integration/main.dart
index 100ab6f..e0fbc80 100644
--- a/pkg/analysis_server/benchmark/integration/main.dart
+++ b/pkg/analysis_server/benchmark/integration/main.dart
@@ -26,8 +26,7 @@
});
PerfArgs args = parseArgs(rawArgs);
- Driver driver = new Driver(
- diagnosticPort: args.diagnosticPort, newTaskModel: args.newTaskModel);
+ Driver driver = new Driver(diagnosticPort: args.diagnosticPort);
Stream<Operation> stream = openInput(args);
StreamSubscription<Operation> subscription;
subscription = stream.listen((Operation op) {
@@ -57,7 +56,6 @@
const HELP_CMDLINE_OPTION = 'help';
const INPUT_CMDLINE_OPTION = 'input';
const MAP_OPTION = 'map';
-const NEW_TASK_MODEL_OPTION = 'newTaskModel';
/**
* The amount of time to give the server to respond to a shutdown request
@@ -94,10 +92,6 @@
help: '<dirPath>\n'
'The temporary directory containing source used during performance measurement.\n'
'WARNING: The contents of the target directory will be modified');
- _argParser.addFlag(NEW_TASK_MODEL_OPTION,
- help: "enable the use of the new task model",
- defaultsTo: false,
- negatable: false);
_argParser.addOption(DIAGNOSTIC_PORT_OPTION,
abbr: 'd',
help: 'localhost port on which server will provide diagnostic web pages');
@@ -181,8 +175,6 @@
showHelp = true;
}
- perfArgs.newTaskModel = args[NEW_TASK_MODEL_OPTION];
-
String portText = args[DIAGNOSTIC_PORT_OPTION];
if (portText != null) {
perfArgs.diagnosticPort = int.parse(portText, onError: (s) {
@@ -253,9 +245,4 @@
* The diagnostic port for Analysis Server or `null` if none.
*/
int diagnosticPort;
-
- /**
- * `true` if the server should run using the new task model.
- */
- bool newTaskModel;
}
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 68947be..b20b660 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.13.0</h1>
+ <h1 style="color:#999999">Version 1.14.0</h1>
<p>
This document contains a specification of the API provided by the
analysis server. The API in this document is currently under
@@ -2304,7 +2304,27 @@
field is omitted if the file is not an HTML file.
</p>
</dd></dl></dd></dl>
-
+ <h2 class="domain"><a name="domain_diagnostic">Domain: diagnostic</a></h2>
+ <p>
+ The diagnostic domain contains server diagnostics APIs.
+ </p>
+
+ <h3>Requests</h3><dl><dt class="request"><a name="request_diagnostic.getDiagnostics">diagnostic.getDiagnostics</a> (<a href="#request_diagnostic.getDiagnostics">#</a>)</dt><dd><div class="box"><pre>request: {
+ "id": String
+ "method": "diagnostic.getDiagnostics"
+}</pre><br><pre>response: {
+ "id": String
+ "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
+ "result": {
+ "<b>contexts</b>": List<<a href="#type_ContextData">ContextData</a>>
+ }
+}</pre></div>
+ <p>Return server diagnostics.</p>
+
+ <h4>Returns</h4><dl><dt class="field"><b><i>contexts ( List<<a href="#type_ContextData">ContextData</a>> )</i></b></dt><dd>
+
+ <p>The list of analysis contexts.</p>
+ </dd></dl></dd></dl>
<h2 class="domain"><a name="types">Types</a></h2>
<p>
@@ -2755,7 +2775,37 @@
For suggestions of this kind, the completion is
the named argument identifier including a trailing ':' and space.
</p>
- </dd><dt class="value">OPTIONAL_ARGUMENT</dt><dt class="value">PARAMETER</dt></dl></dd><dt class="typeDefinition"><a name="type_Element">Element: object</a></dt><dd>
+ </dd><dt class="value">OPTIONAL_ARGUMENT</dt><dt class="value">PARAMETER</dt></dl></dd><dt class="typeDefinition"><a name="type_ContextData">ContextData: object</a></dt><dd>
+ <p>
+ Information about an analysis context.
+ </p>
+
+ <dl><dt class="field"><b><i>name ( String )</i></b></dt><dd>
+
+ <p>
+ The name of the context.
+ </p>
+ </dd><dt class="field"><b><i>explicitFileCount ( int )</i></b></dt><dd>
+
+ <p>
+ Explicitly analyzed files.
+ </p>
+ </dd><dt class="field"><b><i>implicitFileCount ( int )</i></b></dt><dd>
+
+ <p>
+ Implicitly analyzed files.
+ </p>
+ </dd><dt class="field"><b><i>workItemQueueLength ( int )</i></b></dt><dd>
+
+ <p>
+ The number of work items in the queue.
+ </p>
+ </dd><dt class="field"><b><i>cacheEntryExceptions ( List<String> )</i></b></dt><dd>
+
+ <p>
+ Exceptions associated with cache entries.
+ </p>
+ </dd></dl></dd><dt class="typeDefinition"><a name="type_Element">Element: object</a></dt><dd>
<p>
Information about an element (something that can be declared
in code).
@@ -2858,7 +2908,12 @@
<dl><dt class="value">LIBRARY</dt><dt class="value">PART</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
<p>
- The absolute path of a file.
+ The absolute, normalized path of a file.
+ </p>
+ <p>
+ If the format of a file path in a request is not valid, e.g. the
+ path is not absolute or is not normalized, then an error of type
+ <tt>INVALID_FILE_PATH_FORMAT</tt> will be generated.
</p>
</dd><dt class="typeDefinition"><a name="type_FoldingKind">FoldingKind: String</a></dt><dd>
<p>
@@ -3636,6 +3691,12 @@
The context root used to create an execution context does not
exist.
</p>
+ </dd><dt class="value">INVALID_FILE_PATH_FORMAT</dt><dd>
+
+ <p>
+ The format of the given file path is invalid, e.g. is not
+ absolute and normalized.
+ </p>
</dd><dt class="value">INVALID_OVERLAY_CHANGE</dt><dd>
<p>
@@ -4301,7 +4362,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.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>
+ <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><h4>diagnostic (<a href="#domain_diagnostic">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_diagnostic.getDiagnostics">getDiagnostics</a></li></ul></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_ContextData">ContextData</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/protocol/generated_protocol.dart b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
index 81ad8dc..e931ba3 100644
--- a/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/generated_protocol.dart
@@ -9447,7 +9447,6 @@
* "explicitFileCount": int
* "implicitFileCount": int
* "workItemQueueLength": int
- * "workItemQueueLengthAverage": String
* "cacheEntryExceptions": List<String>
* }
*
@@ -9462,8 +9461,6 @@
int _workItemQueueLength;
- String _workItemQueueLengthAverage;
-
List<String> _cacheEntryExceptions;
/**
@@ -9519,21 +9516,6 @@
}
/**
- * 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;
@@ -9546,12 +9528,11 @@
this._cacheEntryExceptions = value;
}
- ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, String workItemQueueLengthAverage, List<String> cacheEntryExceptions) {
+ ContextData(String name, int explicitFileCount, int implicitFileCount, int workItemQueueLength, List<String> cacheEntryExceptions) {
this.name = name;
this.explicitFileCount = explicitFileCount;
this.implicitFileCount = implicitFileCount;
this.workItemQueueLength = workItemQueueLength;
- this.workItemQueueLengthAverage = workItemQueueLengthAverage;
this.cacheEntryExceptions = cacheEntryExceptions;
}
@@ -9584,19 +9565,13 @@
} 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, workItemQueueLengthAverage, cacheEntryExceptions);
+ return new ContextData(name, explicitFileCount, implicitFileCount, workItemQueueLength, cacheEntryExceptions);
} else {
throw jsonDecoder.mismatch(jsonPath, "ContextData", json);
}
@@ -9608,7 +9583,6 @@
result["explicitFileCount"] = explicitFileCount;
result["implicitFileCount"] = implicitFileCount;
result["workItemQueueLength"] = workItemQueueLength;
- result["workItemQueueLengthAverage"] = workItemQueueLengthAverage;
result["cacheEntryExceptions"] = cacheEntryExceptions;
return result;
}
@@ -9623,7 +9597,6 @@
explicitFileCount == other.explicitFileCount &&
implicitFileCount == other.implicitFileCount &&
workItemQueueLength == other.workItemQueueLength &&
- workItemQueueLengthAverage == other.workItemQueueLengthAverage &&
listEqual(cacheEntryExceptions, other.cacheEntryExceptions, (String a, String b) => a == b);
}
return false;
@@ -9636,7 +9609,6 @@
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);
}
@@ -14093,6 +14065,7 @@
* GET_REACHABLE_SOURCES_INVALID_FILE
* INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
+ * INVALID_FILE_PATH_FORMAT
* INVALID_OVERLAY_CHANGE
* INVALID_PARAMETER
* INVALID_REQUEST
@@ -14166,6 +14139,12 @@
static const INVALID_EXECUTION_CONTEXT = const RequestErrorCode._("INVALID_EXECUTION_CONTEXT");
/**
+ * The format of the given file path is invalid, e.g. is not absolute and
+ * normalized.
+ */
+ static const INVALID_FILE_PATH_FORMAT = const RequestErrorCode._("INVALID_FILE_PATH_FORMAT");
+
+ /**
* An "analysis.updateContent" request contained a ChangeContentOverlay
* object which can't be applied, due to an edit having an offset or length
* that is out of range.
@@ -14260,7 +14239,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, 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];
+ 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_FILE_PATH_FORMAT, 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;
@@ -14286,6 +14265,8 @@
return INVALID_ANALYSIS_ROOT;
case "INVALID_EXECUTION_CONTEXT":
return INVALID_EXECUTION_CONTEXT;
+ case "INVALID_FILE_PATH_FORMAT":
+ return INVALID_FILE_PATH_FORMAT;
case "INVALID_OVERLAY_CHANGE":
return INVALID_OVERLAY_CHANGE;
case "INVALID_PARAMETER":
diff --git a/pkg/analysis_server/lib/plugin/protocol/protocol.dart b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
index 5617efc..9daa9f0 100644
--- a/pkg/analysis_server/lib/plugin/protocol/protocol.dart
+++ b/pkg/analysis_server/lib/plugin/protocol/protocol.dart
@@ -441,6 +441,15 @@
"Invalid execution context: $contextId"));
/**
+ * Initialize a newly created instance to represent the
+ * INVALID_FILE_PATH_FORMAT error condition.
+ */
+ Response.invalidFilePathFormat(Request request, path)
+ : this(request.id,
+ error: new RequestError(RequestErrorCode.INVALID_FILE_PATH_FORMAT,
+ 'Invalid file path format: $path'));
+
+ /**
* Initialize a newly created instance to represent an error condition caused
* by a [request] that had invalid parameter. [path] is the path to the
* invalid parameter, in Javascript notation (e.g. "foo.bar" means that the
diff --git a/pkg/analysis_server/lib/src/analysis_logger.dart b/pkg/analysis_server/lib/src/analysis_logger.dart
index bc2276e..8b9c9b6 100644
--- a/pkg/analysis_server/lib/src/analysis_logger.dart
+++ b/pkg/analysis_server/lib/src/analysis_logger.dart
@@ -47,11 +47,6 @@
}
@override
- void logError2(String message, Object exception) {
- baseLogger.severe(message, exception);
- }
-
- @override
void logInformation(String message, [CaughtException exception]) {
if (exception == null) {
baseLogger.info(message);
@@ -59,9 +54,4 @@
baseLogger.info(message, exception.exception, exception.stackTrace);
}
}
-
- @override
- void logInformation2(String message, Object exception) {
- baseLogger.info(message, exception);
- }
}
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 6a5ace1..f72f051 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -72,7 +72,7 @@
* The version of the analysis server. The value should be replaced
* automatically during the build.
*/
- static final String VERSION = '1.12.0';
+ static final String VERSION = '1.14.0';
/**
* The number of milliseconds to perform operations before inserting
@@ -185,8 +185,8 @@
* A table mapping [AnalysisContext]s to the completers that should be
* completed when analysis of this context is finished.
*/
- Map<AnalysisContext,
- Completer<AnalysisDoneReason>> contextAnalysisDoneCompleters =
+ Map<AnalysisContext, Completer<AnalysisDoneReason>>
+ contextAnalysisDoneCompleters =
new HashMap<AnalysisContext, Completer<AnalysisDoneReason>>();
/**
@@ -732,6 +732,15 @@
}
/**
+ * Return `true` if the given path is a valid `FilePath`.
+ *
+ * This means that it is absolute and normalized.
+ */
+ bool isValidFilePath(String path) {
+ return resourceProvider.absolutePathContext.isValid(path);
+ }
+
+ /**
* Returns a [Future] completing when [file] has been completely analyzed, in
* particular, all its errors have been computed. The future is completed
* with an [AnalysisDoneReason] indicating what caused the file's analysis to
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 061cc23..15e3c80 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -539,7 +539,7 @@
*/
void processOptionsForContext(ContextInfo info, Folder folder,
{bool optionsRemoved: false}) {
- Map<String, YamlNode> options;
+ Map<String, Object> options;
try {
options = analysisOptionsProvider.getOptions(folder);
} catch (_) {
@@ -550,6 +550,24 @@
return;
}
+ // In case options files are removed, revert to defaults.
+ if (optionsRemoved) {
+ // Start with defaults.
+ info.context.analysisOptions = new AnalysisOptionsImpl();
+
+ // Apply inherited options.
+ options = _getEmbeddedOptions(info.context);
+ if (options != null) {
+ configureContextOptions(info.context, options);
+ }
+ } else {
+ // Check for embedded options.
+ YamlMap embeddedOptions = _getEmbeddedOptions(info.context);
+ if (embeddedOptions != null) {
+ options = new Merger().merge(embeddedOptions, options);
+ }
+ }
+
// Notify options processors.
AnalysisEngine.instance.optionsPlugin.optionsProcessors
.forEach((OptionsProcessor p) {
@@ -562,34 +580,19 @@
}
});
- // In case options files are removed, revert to defaults.
- if (optionsRemoved) {
- // Start with defaults.
- info.context.analysisOptions = new AnalysisOptionsImpl();
+ configureContextOptions(info.context, options);
- // Apply inherited options.
- YamlMap embeddedOptions = _getEmbeddedOptions(info.context);
- if (embeddedOptions != null) {
- configureContextOptions(info.context, embeddedOptions);
- }
+ // Nothing more to do.
+ if (options == null) {
return;
}
- // Check for embedded options.
- YamlMap embeddedOptions = _getEmbeddedOptions(info.context);
- if (embeddedOptions != null) {
- options = new Merger().merge(embeddedOptions, options);
- }
-
- // Analysis options are processed 'in-line'.
var analyzer = options[AnalyzerOptions.analyzer];
if (analyzer is! Map) {
- // No options for analyzer.
+ // Done.
return;
}
- configureContextOptions(info.context, options);
-
// Set ignore patterns.
YamlList exclude = analyzer[AnalyzerOptions.exclude];
if (exclude != null) {
diff --git a/pkg/analysis_server/lib/src/domain_analysis.dart b/pkg/analysis_server/lib/src/domain_analysis.dart
index f1bdf14..19cf98e 100644
--- a/pkg/analysis_server/lib/src/domain_analysis.dart
+++ b/pkg/analysis_server/lib/src/domain_analysis.dart
@@ -65,7 +65,8 @@
if (errorInfo == null) {
server.sendResponse(new Response.getErrorsInvalidFile(request));
} else {
- errors = doAnalysisError_listFromEngine(
+ engine.AnalysisContext context = server.getAnalysisContext(file);
+ errors = doAnalysisError_listFromEngine(context,
errorInfo.lineInfo, errorInfo.errors);
server.sendResponse(
new AnalysisGetErrorsResult(errors).toResponse(request.id));
@@ -175,8 +176,9 @@
if (pair.context == null || pair.source == null) {
return new Response.getReachableSourcesInvalidFile(request);
}
- Map<String, List<String>> sources = new ReachableSourceCollector(
- pair.source, pair.context).collectSources();
+ Map<String, List<String>> sources =
+ new ReachableSourceCollector(pair.source, pair.context)
+ .collectSources();
return new AnalysisGetReachableSourcesResult(sources)
.toResponse(request.id);
}
@@ -245,9 +247,22 @@
*/
Response setAnalysisRoots(Request request) {
var params = new AnalysisSetAnalysisRootsParams.fromRequest(request);
+ List<String> includedPathList = params.included;
+ List<String> excludedPathList = params.excluded;
+ // validate
+ for (String path in includedPathList) {
+ if (!server.isValidFilePath(path)) {
+ return new Response.invalidFilePathFormat(request, path);
+ }
+ }
+ for (String path in excludedPathList) {
+ if (!server.isValidFilePath(path)) {
+ return new Response.invalidFilePathFormat(request, path);
+ }
+ }
// continue in server
- server.setAnalysisRoots(request.id, params.included, params.excluded,
- params.packageRoots == null ? {} : params.packageRoots);
+ server.setAnalysisRoots(request.id, includedPathList, excludedPathList,
+ params.packageRoots ?? <String, String>{});
return new AnalysisSetAnalysisRootsResult().toResponse(request.id);
}
@@ -347,8 +362,8 @@
class AnalysisDomainImpl implements AnalysisDomain {
final AnalysisServer server;
- final Map<ResultDescriptor,
- StreamController<engine.ComputedResult>> controllers =
+ final Map<ResultDescriptor, StreamController<engine.ComputedResult>>
+ controllers =
<ResultDescriptor, StreamController<engine.ComputedResult>>{};
AnalysisDomainImpl(this.server) {
diff --git a/pkg/analysis_server/lib/src/domain_diagnostic.dart b/pkg/analysis_server/lib/src/domain_diagnostic.dart
index 5d30d92..e9bd0c3 100644
--- a/pkg/analysis_server/lib/src/domain_diagnostic.dart
+++ b/pkg/analysis_server/lib/src/domain_diagnostic.dart
@@ -2,20 +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.
-library src.domain_diagnostic;
+library analysis_server.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';
-import 'package:analyzer/src/generated/engine.dart'
- hide AnalysisCache, AnalysisContextImpl;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/task/driver.dart';
@@ -36,20 +33,12 @@
/// 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(folder, context));
@@ -63,11 +52,9 @@
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>();
@@ -92,7 +79,7 @@
}
}
return new ContextData(context.name, explicitFiles, implicitFiles,
- workItems, workItemAverage, exceptions.toList());
+ workItems, exceptions.toList());
}
@override
@@ -108,83 +95,3 @@
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/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index c2f8a5a..3988de2 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -161,8 +161,7 @@
String filePath = source.fullName;
// check files
bool isDartFile = notice.resolvedDartUnit != null;
- bool isHtmlFile = notice.resolvedHtmlUnit != null;
- if (!isDartFile && !isHtmlFile) {
+ if (!isDartFile) {
return;
}
// prepare context
@@ -184,10 +183,6 @@
server.sendNotification(
new ExecutionLaunchDataParams(filePath, kind: kind)
.toNotification());
- } else if (isHtmlFile) {
- List<Source> libraries = context.getLibrariesReferencedFromHtml(source);
- server.sendNotification(new ExecutionLaunchDataParams(filePath,
- referencedFiles: _getFullNames(libraries)).toNotification());
}
});
}
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index 1865146..93ad959 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -250,15 +250,20 @@
if (!engine.AnalysisEngine.isDartFileName(file)) {
return new Response.sortMembersInvalidFile(request);
}
- // prepare resolved units
- List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
- if (units.isEmpty) {
+ // prepare location
+ ContextSourcePair contextSource = server.getContextSourcePair(file);
+ engine.AnalysisContext context = contextSource.context;
+ Source source = contextSource.source;
+ if (context == null || source == null) {
return new Response.sortMembersInvalidFile(request);
}
- // prepare context
- CompilationUnit unit = units.first;
- engine.AnalysisContext context = unit.element.context;
- Source source = unit.element.source;
+ // prepare parsed unit
+ CompilationUnit unit;
+ try {
+ unit = context.parseCompilationUnit(source);
+ } catch (e) {
+ return new Response.sortMembersInvalidFile(request);
+ }
// check if there are scan/parse errors in the file
engine.AnalysisErrorInfo errors = context.getErrors(source);
int numScanParseErrors = _getNumberOfScanParseErrors(errors.errors);
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
deleted file mode 100644
index fbf70a1..0000000
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ /dev/null
@@ -1,1655 +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 analysis_server.src.get_handler;
-
-import 'dart:async';
-import 'dart:collection';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:math';
-
-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_execution.dart';
-import 'package:analysis_server/src/operation/operation.dart';
-import 'package:analysis_server/src/operation/operation_analysis.dart';
-import 'package:analysis_server/src/operation/operation_queue.dart';
-import 'package:analysis_server/src/services/index/index.dart';
-import 'package:analysis_server/src/services/index/local_index.dart';
-import 'package:analysis_server/src/services/index/store/split_store.dart';
-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:analyzer/file_system/file_system.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/java_engine.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
-import 'package:analyzer/task/model.dart' as newTask;
-import 'package:plugin/plugin.dart';
-
-/**
- * A function that can be used to generate HTML output into the given [buffer].
- * The HTML that is generated must be valid (special characters must already be
- * encoded).
- */
-typedef void HtmlGenerator(StringBuffer buffer);
-
-/**
- * Instances of the class [GetHandler] handle GET requests.
- */
-class GetHandler {
- /**
- * The path used to request overall performance information.
- */
- static const String ANALYSIS_PERFORMANCE_PATH = '/perf/analysis';
-
- /**
- * The path used to request information about a element model.
- */
- static const String AST_PATH = '/ast';
-
- /**
- * The path used to request information about the cache entry corresponding
- * to a single file.
- */
- static const String CACHE_ENTRY_PATH = '/cache_entry';
-
- /**
- * The path used to request the list of source files in a certain cache
- * state.
- */
- static const String CACHE_STATE_PATH = '/cache_state';
-
- /**
- * The path used to request code completion information.
- */
- static const String COMPLETION_PATH = '/completion';
-
- /**
- * The path used to request communication performance information.
- */
- static const String COMMUNICATION_PERFORMANCE_PATH = '/perf/communication';
-
- /**
- * The path used to request information about a specific context.
- */
- static const String CONTEXT_PATH = '/context';
-
- /**
- * The path used to request information about a element model.
- */
- static const String ELEMENT_PATH = '/element';
-
- /**
- * The path used to request information about elements with the given name.
- */
- static const String INDEX_ELEMENT_BY_NAME = '/index/element-by-name';
-
- /**
- * The path used to request an overlay contents.
- */
- static const String OVERLAY_PATH = '/overlay';
-
- /**
- * The path used to request overlays information.
- */
- static const String OVERLAYS_PATH = '/overlays';
-
- /**
- * The path used to request the status of the analysis server as a whole.
- */
- static const String STATUS_PATH = '/status';
-
- /**
- * Query parameter used to represent the context to search for, when
- * accessing [CACHE_ENTRY_PATH] or [CACHE_STATE_PATH].
- */
- static const String CONTEXT_QUERY_PARAM = 'context';
-
- /**
- * Query parameter used to represent the descriptor to search for, when
- * accessing [CACHE_STATE_PATH].
- */
- static const String DESCRIPTOR_QUERY_PARAM = 'descriptor';
-
- /**
- * Query parameter used to represent the name of elements to search for, when
- * accessing [INDEX_ELEMENT_BY_NAME].
- */
- static const String INDEX_ELEMENT_NAME = 'name';
-
- /**
- * Query parameter used to represent the path of an overlayed file.
- */
- static const String PATH_PARAM = 'path';
-
- /**
- * Query parameter used to represent the source to search for, when accessing
- * [CACHE_ENTRY_PATH].
- */
- static const String SOURCE_QUERY_PARAM = 'entry';
-
- /**
- * Query parameter used to represent the cache state to search for, when
- * accessing [CACHE_STATE_PATH].
- */
- static const String STATE_QUERY_PARAM = 'state';
-
- static final ContentType _htmlContent =
- new ContentType("text", "html", charset: "utf-8");
-
- /**
- * The socket server whose status is to be reported on.
- */
- SocketServer _server;
-
- /**
- * Buffer containing strings printed by the analysis server.
- */
- List<String> _printBuffer;
-
- /**
- * Contents of overlay files.
- */
- final Map<String, String> _overlayContents = <String, String>{};
-
- /**
- * Initialize a newly created handler for GET requests.
- */
- GetHandler(this._server, this._printBuffer);
-
- /**
- * Return the active [CompletionDomainHandler]
- * or `null` if either analysis server is not running
- * or there is no completion domain handler.
- */
- CompletionDomainHandler get _completionDomainHandler {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return null;
- }
- return analysisServer.handlers
- .firstWhere((h) => h is CompletionDomainHandler, orElse: () => null);
- }
-
- /**
- * Handle a GET request received by the HTTP server.
- */
- void handleGetRequest(HttpRequest request) {
- String path = request.uri.path;
- if (path == STATUS_PATH) {
- _returnServerStatus(request);
- } else if (path == ANALYSIS_PERFORMANCE_PATH) {
- _returnAnalysisPerformance(request);
- } else if (path == AST_PATH) {
- _returnAst(request);
- } else if (path == CACHE_STATE_PATH) {
- _returnCacheState(request);
- } else if (path == CACHE_ENTRY_PATH) {
- _returnCacheEntry(request);
- } else if (path == COMPLETION_PATH) {
- _returnCompletionInfo(request);
- } else if (path == COMMUNICATION_PERFORMANCE_PATH) {
- _returnCommunicationPerformance(request);
- } else if (path == CONTEXT_PATH) {
- _returnContextInfo(request);
- } else if (path == ELEMENT_PATH) {
- _returnElement(request);
- } else if (path == INDEX_ELEMENT_BY_NAME) {
- _returnIndexElementByName(request);
- } else if (path == OVERLAY_PATH) {
- _returnOverlayContents(request);
- } else if (path == OVERLAYS_PATH) {
- _returnOverlaysInfo(request);
- } else {
- _returnUnknownRequest(request);
- }
- }
-
- /**
- * Return the folder being managed by the given [analysisServer] that matches
- * the given [contextFilter], or `null` if there is none.
- */
- Folder _findFolder(AnalysisServer analysisServer, String contextFilter) {
- return analysisServer.folderMap.keys.firstWhere(
- (Folder folder) => folder.path == contextFilter,
- orElse: () => null);
- }
-
- /**
- * Return `true` if the given analysis [context] has at least one entry with
- * an exception.
- */
- bool _hasException(AnalysisContextImpl context) {
- bool hasException = false;
- context.visitCacheItems((Source source, SourceEntry sourceEntry,
- DataDescriptor rowDesc, CacheState state) {
- if (sourceEntry.exception != null) {
- hasException = true;
- }
- });
- return hasException;
- }
-
- /**
- * Return the folder in the [folderMap] with which the given [context] is
- * associated.
- */
- Folder _keyForValue(
- Map<Folder, AnalysisContext> folderMap, AnalysisContext context) {
- for (Folder folder in folderMap.keys) {
- if (folderMap[folder] == context) {
- return folder;
- }
- }
- return null;
- }
-
- /**
- * Return a response displaying overall performance information.
- */
- void _returnAnalysisPerformance(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server is not running');
- }
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Analysis Performance', [],
- (StringBuffer buffer) {
- buffer.write('<h3>Analysis Performance</h3>');
-
- //
- // Write performance tags.
- //
- {
- buffer.write('<p><b>Time spent in each phase of analysis</b></p>');
- buffer.write(
- '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
- _writeRow(buffer, ['Time (in ms)', 'Percent', 'Analysis Phase'],
- header: true);
- // prepare sorted tags
- List<PerformanceTag> tags = PerformanceTag.all.toList();
- tags.remove(ServerPerformanceStatistics.idle);
- tags.sort((a, b) => b.elapsedMs - a.elapsedMs);
- // prepare total time
- int totalTime = 0;
- tags.forEach((PerformanceTag tag) {
- totalTime += tag.elapsedMs;
- });
- // write rows
- void writeRow(PerformanceTag tag) {
- double percent = (tag.elapsedMs * 100) / totalTime;
- String percentStr = '${percent.toStringAsFixed(2)}%';
- _writeRow(buffer, [tag.elapsedMs, percentStr, tag.label],
- classes: ["right", "right", null]);
- }
- tags.forEach(writeRow);
- buffer.write('</table>');
- }
-
- //
- // Write new task model timing information.
- //
- if (AnalysisEngine.instance.useTaskModel) {
- buffer.write('<p><b>Task performace data</b></p>');
- buffer.write(
- '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
- _writeRow(
- buffer,
- [
- 'Task Name',
- 'Count',
- 'Total Time (in ms)',
- 'Average Time (in ms)'
- ],
- header: true);
-
- Map<Type, int> countMap = newTask.AnalysisTask.countMap;
- Map<Type, Stopwatch> stopwatchMap = newTask.AnalysisTask.stopwatchMap;
- List<Type> taskClasses = stopwatchMap.keys.toList();
- taskClasses.sort((Type first, Type second) =>
- first.toString().compareTo(second.toString()));
- int totalTime = 0;
- taskClasses.forEach((Type taskClass) {
- int count = countMap[taskClass];
- if (count == null) {
- count = 0;
- }
- int taskTime = stopwatchMap[taskClass].elapsedMilliseconds;
- totalTime += taskTime;
- _writeRow(buffer, [
- taskClass.toString(),
- count,
- taskTime,
- count <= 0 ? '-' : (taskTime / count).toStringAsFixed(3)
- ], classes: [
- null,
- "right",
- "right",
- "right"
- ]);
- });
- _writeRow(buffer, ['Total', '-', totalTime, '-'],
- classes: [null, "right", "right", "right"]);
- buffer.write('</table>');
- }
-
- //
- // Write old task model transition information.
- //
- {
- Map<DataDescriptor, Map<CacheState, int>> transitionMap =
- SourceEntry.transitionMap;
- buffer.write(
- '<p><b>Number of times a state transitioned to VALID (grouped by descriptor)</b></p>');
- if (transitionMap.isEmpty) {
- buffer.write('<p>none</p>');
- } else {
- List<DataDescriptor> descriptors = transitionMap.keys.toList();
- descriptors.sort((DataDescriptor first, DataDescriptor second) =>
- first.toString().compareTo(second.toString()));
- for (DataDescriptor key in descriptors) {
- Map<CacheState, int> countMap = transitionMap[key];
- List<CacheState> oldStates = countMap.keys.toList();
- oldStates.sort((CacheState first, CacheState second) =>
- first.toString().compareTo(second.toString()));
- buffer.write('<p>${key.toString()}</p>');
- buffer.write(
- '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
- _writeRow(buffer, ['Count', 'Previous State'], header: true);
- for (CacheState state in oldStates) {
- _writeRow(buffer, [countMap[state], state.toString()],
- classes: ["right", null]);
- }
- buffer.write('</table>');
- }
- }
- }
- });
- });
- }
-
- /**
- * Return a response containing information about an AST structure.
- */
- void _returnAst(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
- if (contextFilter == null) {
- return _returnFailure(
- request, 'Query parameter $CONTEXT_QUERY_PARAM required');
- }
- Folder folder = _findFolder(analysisServer, contextFilter);
- if (folder == null) {
- return _returnFailure(request, 'Invalid context: $contextFilter');
- }
- String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
- if (sourceUri == null) {
- return _returnFailure(
- request, 'Query parameter $SOURCE_QUERY_PARAM required');
- }
-
- AnalysisContextImpl context = analysisServer.folderMap[folder];
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - AST Structure',
- ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
- Source source = context.sourceFactory.forUri(sourceUri);
- if (source == null) {
- buffer.write('<p>Not found.</p>');
- return;
- }
- SourceEntry entry = context.getReadableSourceEntryOrNull(source);
- if (entry == null) {
- buffer.write('<p>Not found.</p>');
- return;
- }
- CompilationUnit ast = (entry as DartEntry).anyParsedCompilationUnit;
- if (ast == null) {
- buffer.write('<p>null</p>');
- return;
- }
- AstWriter writer = new AstWriter(buffer);
- ast.accept(writer);
- if (writer.exceptions.isNotEmpty) {
- buffer.write('<h3>Exceptions while creating page</h3>');
- for (CaughtException exception in writer.exceptions) {
- _writeException(buffer, exception);
- }
- }
- });
- });
- }
-
- /**
- * Return a response containing information about a single source file in the
- * cache.
- */
- void _returnCacheEntry(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
- if (contextFilter == null) {
- return _returnFailure(
- request, 'Query parameter $CONTEXT_QUERY_PARAM required');
- }
- Folder folder = _findFolder(analysisServer, contextFilter);
- if (folder == null) {
- return _returnFailure(request, 'Invalid context: $contextFilter');
- }
- String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
- if (sourceUri == null) {
- return _returnFailure(
- request, 'Query parameter $SOURCE_QUERY_PARAM required');
- }
-
- List<Folder> allContexts = <Folder>[];
- Map<Folder, SourceEntry> entryMap = new HashMap<Folder, SourceEntry>();
- analysisServer.folderMap
- .forEach((Folder folder, AnalysisContextImpl context) {
- Source source = context.sourceFactory.forUri(sourceUri);
- if (source != null) {
- SourceEntry entry = context.getReadableSourceEntryOrNull(source);
- if (entry != null) {
- allContexts.add(folder);
- entryMap[folder] = entry;
- }
- }
- });
- allContexts.sort((Folder firstFolder, Folder secondFolder) =>
- firstFolder.path.compareTo(secondFolder.path));
- AnalysisContextImpl context = analysisServer.folderMap[folder];
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Cache Entry',
- ['Context: $contextFilter', 'File: $sourceUri'], (HttpResponse) {
- buffer.write('<h3>Analyzing Contexts</h3><p>');
- bool first = true;
- allContexts.forEach((Folder folder) {
- if (first) {
- first = false;
- } else {
- buffer.write('<br>');
- }
- AnalysisContextImpl analyzingContext =
- analysisServer.folderMap[folder];
- if (analyzingContext == context) {
- buffer.write(folder.path);
- } else {
- buffer.write(makeLink(
- CACHE_ENTRY_PATH,
- {
- CONTEXT_QUERY_PARAM: folder.path,
- SOURCE_QUERY_PARAM: sourceUri
- },
- HTML_ESCAPE.convert(folder.path)));
- }
- if (entryMap[folder].explicitlyAdded) {
- buffer.write(' (explicit)');
- } else {
- buffer.write(' (implicit)');
- }
- });
- buffer.write('</p>');
-
- SourceEntry entry = entryMap[folder];
- if (entry == null) {
- buffer.write('<p>Not being analyzed in this context.</p>');
- return;
- }
- Map<String, String> linkParameters = <String, String>{
- CONTEXT_QUERY_PARAM: folder.path,
- SOURCE_QUERY_PARAM: sourceUri
- };
-
- buffer.write('<h3>Library Independent</h3>');
- _writeDescriptorTable(buffer, entry.descriptors, entry.getState,
- entry.getValue, linkParameters);
- if (entry is DartEntry) {
- for (Source librarySource in entry.containingLibraries) {
- String libraryName = HTML_ESCAPE.convert(librarySource.fullName);
- buffer.write('<h3>In library $libraryName:</h3>');
- _writeDescriptorTable(
- buffer,
- entry.libraryDescriptors,
- (DataDescriptor descriptor) =>
- entry.getStateInLibrary(descriptor, librarySource),
- (DataDescriptor descriptor) =>
- entry.getValueInLibrary(descriptor, librarySource),
- linkParameters);
- }
- }
- if (entry.exception != null) {
- buffer.write('<h3>Exception</h3>');
- _writeException(buffer, entry.exception);
- }
- });
- });
- }
-
- /**
- * Return a response indicating the set of source files in a certain cache
- * state.
- */
- void _returnCacheState(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- // Figure out which context is being searched within.
- String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
- if (contextFilter == null) {
- return _returnFailure(
- request, 'Query parameter $CONTEXT_QUERY_PARAM required');
- }
- // Figure out what CacheState is being searched for.
- String stateQueryParam = request.uri.queryParameters[STATE_QUERY_PARAM];
- if (stateQueryParam == null) {
- return _returnFailure(
- request, 'Query parameter $STATE_QUERY_PARAM required');
- }
- CacheState stateFilter = null;
- for (CacheState value in CacheState.values) {
- if (value.toString() == stateQueryParam) {
- stateFilter = value;
- }
- }
- if (stateFilter == null) {
- return _returnFailure(
- request, 'Query parameter $STATE_QUERY_PARAM is invalid');
- }
- // Figure out which descriptor is being searched for.
- String descriptorFilter =
- request.uri.queryParameters[DESCRIPTOR_QUERY_PARAM];
- if (descriptorFilter == null) {
- return _returnFailure(
- request, 'Query parameter $DESCRIPTOR_QUERY_PARAM required');
- }
-
- Folder folder = _findFolder(analysisServer, contextFilter);
- AnalysisContextImpl context = analysisServer.folderMap[folder];
- List<String> links = <String>[];
- context.visitCacheItems((Source source, SourceEntry dartEntry,
- DataDescriptor rowDesc, CacheState state) {
- if (state != stateFilter || rowDesc.toString() != descriptorFilter) {
- return;
- }
- String link = makeLink(
- CACHE_ENTRY_PATH,
- {
- CONTEXT_QUERY_PARAM: folder.path,
- SOURCE_QUERY_PARAM: source.uri.toString()
- },
- HTML_ESCAPE.convert(source.fullName));
- links.add(link);
- });
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Cache Search', [
- 'Context: $contextFilter',
- 'Descriptor: ${HTML_ESCAPE.convert(descriptorFilter)}',
- 'State: ${HTML_ESCAPE.convert(stateQueryParam)}'
- ], (StringBuffer buffer) {
- buffer.write('<p>${links.length} files found</p>');
- buffer.write('<ul>');
- links.forEach((String link) {
- buffer.write('<li>$link</li>');
- });
- buffer.write('</ul>');
- });
- });
- }
-
- /**
- * Return a response displaying overall performance information.
- */
- void _returnCommunicationPerformance(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server is not running');
- }
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Communication Performance', [],
- (StringBuffer buffer) {
- buffer.write('<h3>Communication Performance</h3>');
- _writeTwoColumns(buffer, (StringBuffer buffer) {
- ServerPerformance perf = analysisServer.performanceDuringStartup;
- int requestCount = perf.requestCount;
- num averageLatency = requestCount > 0
- ? (perf.requestLatency / requestCount).round()
- : 0;
- int maximumLatency = perf.maxLatency;
- num slowRequestPercent = requestCount > 0
- ? (perf.slowRequestCount * 100 / requestCount).round()
- : 0;
- buffer.write('<h4>Startup</h4>');
- buffer.write('<table>');
- _writeRow(buffer, [requestCount, 'requests'],
- classes: ["right", null]);
- _writeRow(buffer, [averageLatency, 'ms average latency'],
- classes: ["right", null]);
- _writeRow(buffer, [maximumLatency, 'ms maximum latency'],
- classes: ["right", null]);
- _writeRow(buffer, [slowRequestPercent, '% > 150 ms latency'],
- classes: ["right", null]);
- if (analysisServer.performanceAfterStartup != null) {
- int startupTime = analysisServer.performanceAfterStartup.startTime -
- perf.startTime;
- _writeRow(
- buffer, [startupTime, 'ms for initial analysis to complete']);
- }
- buffer.write('</table>');
- }, (StringBuffer buffer) {
- ServerPerformance perf = analysisServer.performanceAfterStartup;
- if (perf == null) {
- return;
- }
- int requestCount = perf.requestCount;
- num averageLatency = requestCount > 0
- ? (perf.requestLatency * 10 / requestCount).round() / 10
- : 0;
- int maximumLatency = perf.maxLatency;
- num slowRequestPercent = requestCount > 0
- ? (perf.slowRequestCount * 100 / requestCount).round()
- : 0;
- buffer.write('<h4>Current</h4>');
- buffer.write('<table>');
- _writeRow(buffer, [requestCount, 'requests'],
- classes: ["right", null]);
- _writeRow(buffer, [averageLatency, 'ms average latency'],
- classes: ["right", null]);
- _writeRow(buffer, [maximumLatency, 'ms maximum latency'],
- classes: ["right", null]);
- _writeRow(buffer, [slowRequestPercent, '% > 150 ms latency'],
- classes: ["right", null]);
- buffer.write('</table>');
- });
- });
- });
- }
-
- /**
- * Return a response displaying code completion information.
- */
- void _returnCompletionInfo(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 - Completion Stats', [],
- (StringBuffer buffer) {
- _writeCompletionPerformanceDetail(buffer, index);
- _writeCompletionPerformanceList(buffer);
- });
- });
- }
-
- /**
- * Return a response containing information about a single source file in the
- * cache.
- */
- void _returnContextInfo(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
- if (contextFilter == null) {
- return _returnFailure(
- request, 'Query parameter $CONTEXT_QUERY_PARAM required');
- }
- Folder folder = _findFolder(analysisServer, contextFilter);
- if (folder == null) {
- return _returnFailure(request, 'Invalid context: $contextFilter');
- }
-
- List<String> priorityNames;
- List<String> explicitNames = <String>[];
- List<String> implicitNames = <String>[];
- Map<String, String> links = new HashMap<String, String>();
- List<CaughtException> exceptions = <CaughtException>[];
- AnalysisContextImpl context = analysisServer.folderMap[folder];
- priorityNames = context.prioritySources
- .map((Source source) => source.fullName)
- .toList();
- context.visitCacheItems((Source source, SourceEntry sourceEntry,
- DataDescriptor rowDesc, CacheState state) {
- String sourceName = source.fullName;
- if (!links.containsKey(sourceName)) {
- CaughtException exception = sourceEntry.exception;
- if (exception != null) {
- exceptions.add(exception);
- }
- String link = makeLink(
- CACHE_ENTRY_PATH,
- {
- CONTEXT_QUERY_PARAM: folder.path,
- SOURCE_QUERY_PARAM: source.uri.toString()
- },
- sourceName,
- exception != null);
- if (sourceEntry.explicitlyAdded) {
- explicitNames.add(sourceName);
- } else {
- implicitNames.add(sourceName);
- }
- links[sourceName] = link;
- }
- });
- explicitNames.sort();
- implicitNames.sort();
-
- _overlayContents.clear();
- context.visitContentCache((String fullName, int stamp, String contents) {
- _overlayContents[fullName] = contents;
- });
-
- void _writeFiles(
- StringBuffer buffer, String title, List<String> fileNames) {
- buffer.write('<h3>$title</h3>');
- if (fileNames == null || fileNames.isEmpty) {
- buffer.write('<p>None</p>');
- } else {
- buffer.write('<table style="width: 100%">');
- for (String fileName in fileNames) {
- buffer.write('<tr><td>');
- buffer.write(links[fileName]);
- buffer.write('</td><td>');
- if (_overlayContents.containsKey(fileName)) {
- buffer.write(
- makeLink(OVERLAY_PATH, {PATH_PARAM: fileName}, 'overlay'));
- }
- buffer.write('</td></tr>');
- }
- buffer.write('</table>');
- }
- }
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(
- buffer, 'Analysis Server - Context', ['Context: $contextFilter'],
- (StringBuffer buffer) {
- List headerRowText = ['Context'];
- headerRowText.addAll(CacheState.values);
- buffer.write('<h3>Summary</h3>');
- buffer.write('<table>');
- _writeRow(buffer, headerRowText, header: true);
- AnalysisContextStatistics statistics = context.statistics;
- statistics.cacheRows.forEach((AnalysisContextStatistics_CacheRow row) {
- List rowText = [row.name];
- for (CacheState state in CacheState.values) {
- String text = row.getCount(state).toString();
- Map<String, String> params = <String, String>{
- STATE_QUERY_PARAM: state.toString(),
- CONTEXT_QUERY_PARAM: folder.path,
- DESCRIPTOR_QUERY_PARAM: row.name
- };
- rowText.add(makeLink(CACHE_STATE_PATH, params, text));
- }
- _writeRow(buffer, rowText, classes: [null, "right"]);
- });
- buffer.write('</table>');
-
- _writeFiles(buffer, 'Priority Files', priorityNames);
- _writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
- _writeFiles(buffer, 'Implicitly Analyzed Files', implicitNames);
-
- buffer.write('<h3>Exceptions</h3>');
- if (exceptions.isEmpty) {
- buffer.write('<p>None</p>');
- } else {
- exceptions.forEach((CaughtException exception) {
- _writeException(buffer, exception);
- });
- }
- });
- });
- }
-
- /**
- * Return a response containing information about an element structure.
- */
- void _returnElement(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
- if (contextFilter == null) {
- return _returnFailure(
- request, 'Query parameter $CONTEXT_QUERY_PARAM required');
- }
- Folder folder = _findFolder(analysisServer, contextFilter);
- if (folder == null) {
- return _returnFailure(request, 'Invalid context: $contextFilter');
- }
- String sourceUri = request.uri.queryParameters[SOURCE_QUERY_PARAM];
- if (sourceUri == null) {
- return _returnFailure(
- request, 'Query parameter $SOURCE_QUERY_PARAM required');
- }
-
- AnalysisContextImpl context = analysisServer.folderMap[folder];
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Element Model', [
- 'Context: $contextFilter',
- 'File: $sourceUri'
- ], (StringBuffer buffer) {
- Source source = context.sourceFactory.forUri(sourceUri);
- if (source == null) {
- buffer.write('<p>Not found.</p>');
- return;
- }
- SourceEntry entry = context.getReadableSourceEntryOrNull(source);
- if (entry == null) {
- buffer.write('<p>Not found.</p>');
- return;
- }
- LibraryElement element = entry.getValue(DartEntry.ELEMENT);
- if (element == null) {
- buffer.write('<p>null</p>');
- return;
- }
- element.accept(new ElementWriter(buffer));
- });
- });
- }
-
- void _returnFailure(HttpRequest request, String message) {
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Failure', [],
- (StringBuffer buffer) {
- buffer.write(HTML_ESCAPE.convert(message));
- });
- });
- }
-
- /**
- * Return a response containing information about elements with the given
- * name.
- */
- Future _returnIndexElementByName(HttpRequest request) async {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server not running');
- }
- Index index = analysisServer.index;
- if (index == null) {
- return _returnFailure(request, 'Indexing is disabled');
- }
- String name = request.uri.queryParameters[INDEX_ELEMENT_NAME];
- if (name == null) {
- return _returnFailure(
- request, 'Query parameter $INDEX_ELEMENT_NAME required');
- }
- if (index is LocalIndex) {
- Map<List<String>, List<InspectLocation>> relations =
- await index.findElementsByName(name);
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Index Elements', ['Name: $name'],
- (StringBuffer buffer) {
- buffer.write('<table border="1">');
- _writeRow(buffer, ['Element', 'Relationship', 'Location'],
- header: true);
- relations.forEach(
- (List<String> elementPath, List<InspectLocation> relations) {
- String elementLocation = elementPath.join(' ');
- relations.forEach((InspectLocation location) {
- var relString = location.relationship.identifier;
- var locString = '${location.path} offset=${location.offset} '
- 'length=${location.length} flags=${location.flags}';
- _writeRow(buffer, [elementLocation, relString, locString]);
- });
- });
- buffer.write('</table>');
- });
- });
- } else {
- return _returnFailure(request, 'LocalIndex expected, but $index found.');
- }
- }
-
- void _returnOverlayContents(HttpRequest request) {
- String path = request.requestedUri.queryParameters[PATH_PARAM];
- if (path == null) {
- return _returnFailure(request, 'Query parameter $PATH_PARAM required');
- }
- String contents = _overlayContents[path];
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Overlay', [],
- (StringBuffer buffer) {
- buffer.write('<pre>${HTML_ESCAPE.convert(contents)}</pre>');
- });
- });
- }
-
- /**
- * Return a response displaying overlays information.
- */
- void _returnOverlaysInfo(HttpRequest request) {
- AnalysisServer analysisServer = _server.analysisServer;
- if (analysisServer == null) {
- return _returnFailure(request, 'Analysis server is not running');
- }
-
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Overlays', [],
- (StringBuffer buffer) {
- buffer.write('<table border="1">');
- _overlayContents.clear();
- ContentCache overlayState = analysisServer.overlayState;
- overlayState.accept((String fullName, int stamp, String contents) {
- buffer.write('<tr>');
- String link =
- makeLink(OVERLAY_PATH, {PATH_PARAM: fullName}, fullName);
- DateTime time = new DateTime.fromMillisecondsSinceEpoch(stamp);
- _writeRow(buffer, [link, time]);
- _overlayContents[fullName] = contents;
- });
- int count = _overlayContents.length;
- buffer.write('<tr><td colspan="2">Total: $count entries.</td></tr>');
- buffer.write('</table>');
- });
- });
- }
-
- /**
- * Return a response indicating the status of the analysis server.
- */
- void _returnServerStatus(HttpRequest request) {
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server - Status', [], (StringBuffer buffer) {
- if (_writeServerStatus(buffer)) {
- _writeAnalysisStatus(buffer);
- _writeEditStatus(buffer);
- _writeExecutionStatus(buffer);
- _writePluginStatus(buffer);
- _writeRecentOutput(buffer);
- }
- });
- });
- }
-
- /**
- * Return an error in response to an unrecognized request received by the HTTP
- * server.
- */
- void _returnUnknownRequest(HttpRequest request) {
- _writeResponse(request, (StringBuffer buffer) {
- _writePage(buffer, 'Analysis Server', [], (StringBuffer buffer) {
- buffer.write('<h3>Pages</h3>');
- buffer.write('<p>');
- buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data'));
- buffer.write('</p>');
- buffer.write('<p>');
- buffer
- .write(makeLink(COMMUNICATION_PERFORMANCE_PATH, {}, 'Performance'));
- buffer.write('</p>');
- buffer.write('<p>');
- buffer.write(makeLink(STATUS_PATH, {}, 'Server status'));
- buffer.write('</p>');
- buffer.write('<p>');
- buffer.write(makeLink(OVERLAYS_PATH, {}, 'File overlays'));
- buffer.write('</p>');
- });
- });
- }
-
- /**
- * Return a two digit decimal representation of the given non-negative integer
- * [value].
- */
- String _twoDigit(int value) {
- if (value < 10) {
- return '0$value';
- }
- return value.toString();
- }
-
- /**
- * Write the status of the analysis domain (on the main status page) to the
- * given [buffer] object.
- */
- void _writeAnalysisStatus(StringBuffer buffer) {
- AnalysisServer analysisServer = _server.analysisServer;
- Map<Folder, AnalysisContext> folderMap = analysisServer.folderMap;
- List<Folder> folders = folderMap.keys.toList();
- folders.sort((Folder first, Folder second) =>
- first.shortName.compareTo(second.shortName));
- AnalysisOptionsImpl options = analysisServer.defaultContextOptions;
- ServerOperationQueue operationQueue = analysisServer.operationQueue;
-
- buffer.write('<h3>Analysis Domain</h3>');
- _writeTwoColumns(buffer, (StringBuffer buffer) {
- if (operationQueue.isEmpty) {
- buffer.write('<p>Status: Done analyzing</p>');
- } else {
- ServerOperation operation = operationQueue.peek();
- if (operation is PerformAnalysisOperation) {
- Folder folder = _keyForValue(folderMap, operation.context);
- if (folder == null) {
- buffer.write('<p>Status: Analyzing in unmapped context</p>');
- } else {
- buffer.write('<p>Status: Analyzing in ${folder.path}</p>');
- }
- } else {
- buffer.write('<p>Status: Analyzing</p>');
- }
- }
-
- buffer.write('<p><b>Analysis Contexts</b></p>');
- buffer.write('<p>');
- bool first = true;
- folders.forEach((Folder folder) {
- if (first) {
- first = false;
- } else {
- buffer.write('<br>');
- }
- String key = folder.shortName;
- buffer.write(makeLink(CONTEXT_PATH, {CONTEXT_QUERY_PARAM: folder.path},
- key, _hasException(folderMap[folder])));
- });
- 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>');
-
- buffer.write('<p><b>Performance Data</b></p>');
- buffer.write('<p>');
- buffer.write(makeLink(ANALYSIS_PERFORMANCE_PATH, {}, 'Task data'));
- buffer.write('</p>');
- }, (StringBuffer buffer) {
- _writeSubscriptionMap(
- buffer, AnalysisService.VALUES, analysisServer.analysisServices);
- });
- }
-
- /**
- * Write performance information about a specific completion request
- * to the given [buffer] object.
- */
- void _writeCompletionPerformanceDetail(StringBuffer buffer, int index) {
- CompletionDomainHandler handler = _completionDomainHandler;
- CompletionPerformance performance;
- if (handler != null) {
- List<CompletionPerformance> list = handler.performanceList;
- if (list != null && list.isNotEmpty) {
- performance = list[max(0, min(list.length - 1, index))];
- }
- }
- if (performance == null) {
- buffer.write('<h3>Completion Performance Detail</h3>');
- buffer.write('<p>No completions yet</p>');
- return;
- }
- buffer.write('<h3>Completion Performance Detail</h3>');
- buffer.write('<p>${performance.startTimeAndMs} for ${performance.source}');
- buffer.write('<table>');
- _writeRow(buffer, ['Elapsed', '', 'Operation'], header: true);
- performance.operations.forEach((OperationPerformance op) {
- String elapsed = op.elapsed != null ? op.elapsed.toString() : '???';
- _writeRow(buffer, [elapsed, ' ', op.name]);
- });
- buffer.write('</table>');
- buffer.write('<p><b>Compute Cache Performance</b>: ');
- if (handler.computeCachePerformance == null) {
- buffer.write('none');
- } else {
- int elapsed = handler.computeCachePerformance.elapsedInMilliseconds;
- Source source = handler.computeCachePerformance.source;
- buffer.write(' $elapsed ms for $source');
- }
- buffer.write('</p>');
- }
-
- /**
- * Write a table showing summary information for the last several
- * completion requests to the given [buffer] object.
- */
- void _writeCompletionPerformanceList(StringBuffer buffer) {
- CompletionDomainHandler handler = _completionDomainHandler;
- buffer.write('<h3>Completion Performance List</h3>');
- if (handler == null) {
- return;
- }
- buffer.write('<table>');
- _writeRow(
- buffer,
- [
- 'Start Time',
- '',
- 'First (ms)',
- '',
- 'Complete (ms)',
- '',
- '# Notifications',
- '',
- '# Suggestions',
- '',
- 'Snippet'
- ],
- header: true);
- int index = 0;
- for (CompletionPerformance performance in handler.performanceList) {
- String link = makeLink(COMPLETION_PATH, {'index': '$index'},
- '${performance.startTimeAndMs}');
- _writeRow(buffer, [
- link,
- ' ',
- performance.firstNotificationInMilliseconds,
- ' ',
- performance.elapsedInMilliseconds,
- ' ',
- performance.notificationCount,
- ' ',
- performance.suggestionCount,
- ' ',
- HTML_ESCAPE.convert(performance.snippet)
- ]);
- ++index;
- }
-
- buffer.write('</table>');
- buffer.write('''
- <p><strong>First (ms)</strong> - the number of milliseconds
- from when completion received the request until the first notification
- with completion results was queued for sending back to the client.
- <p><strong>Complete (ms)</strong> - the number of milliseconds
- from when completion received the request until the final notification
- with completion results was queued for sending back to the client.
- <p><strong># Notifications</strong> - the total number of notifications
- sent to the client with completion results for this request.
- <p><strong># Suggestions</strong> - the number of suggestions
- sent to the client in the first notification, followed by a comma,
- followed by the number of suggestions send to the client
- in the last notification. If there is only one notification,
- then there will be only one number in this column.''');
- }
-
- /**
- * Generate a table showing the cache values corresponding to the given
- * [descriptors], using [getState] to get the cache state corresponding to
- * each descriptor, and [getValue] to get the cached value corresponding to
- * each descriptor. Append the resulting HTML to the given [buffer]. The
- * [linkParameters] will be used if the value is too large to be displayed on
- * the current page and needs to be linked to a separate page.
- */
- void _writeDescriptorTable(
- StringBuffer buffer,
- List<DataDescriptor> descriptors,
- CacheState getState(DataDescriptor),
- dynamic getValue(DataDescriptor),
- Map<String, String> linkParameters) {
- buffer.write('<dl>');
- for (DataDescriptor descriptor in descriptors) {
- String descriptorName = HTML_ESCAPE.convert(descriptor.toString());
- String descriptorState =
- HTML_ESCAPE.convert(getState(descriptor).toString());
- buffer.write('<dt>$descriptorName ($descriptorState)</dt><dd>');
- try {
- _writeValueAsHtml(buffer, getValue(descriptor), linkParameters);
- } catch (exception) {
- buffer.write('(${HTML_ESCAPE.convert(exception.toString())})');
- }
- buffer.write('</dd>');
- }
- buffer.write('</dl>');
- }
-
- /**
- * Write the status of the edit domain (on the main status page) to the given
- * [buffer].
- */
- void _writeEditStatus(StringBuffer buffer) {
- buffer.write('<h3>Edit Domain</h3>');
- _writeTwoColumns(buffer, (StringBuffer buffer) {
- buffer.write('<p><b>Performance Data</b></p>');
- buffer.write('<p>');
- buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data'));
- buffer.write('</p>');
- }, (StringBuffer buffer) {});
- }
-
- /**
- * Write a representation of the given [caughtException] to the given
- * [buffer]. If [isCause] is `true`, then the exception was a cause for
- * another exception.
- */
- void _writeException(StringBuffer buffer, CaughtException caughtException,
- {bool isCause: false}) {
- Object exception = caughtException.exception;
-
- if (exception is AnalysisException) {
- buffer.write('<p>');
- if (isCause) {
- buffer.write('Caused by ');
- }
- buffer.write(exception.message);
- buffer.write('</p>');
- _writeStackTrace(buffer, caughtException.stackTrace);
- CaughtException cause = exception.cause;
- if (cause != null) {
- buffer.write('<blockquote>');
- _writeException(buffer, cause, isCause: true);
- buffer.write('</blockquote>');
- }
- } else {
- buffer.write('<p>');
- if (isCause) {
- buffer.write('Caused by ');
- }
- buffer.write(exception.toString());
- buffer.write('<p>');
- _writeStackTrace(buffer, caughtException.stackTrace);
- }
- }
-
- /**
- * Write the status of the execution domain (on the main status page) to the
- * given [buffer].
- */
- void _writeExecutionStatus(StringBuffer buffer) {
- AnalysisServer analysisServer = _server.analysisServer;
- ExecutionDomainHandler handler = analysisServer.handlers.firstWhere(
- (RequestHandler handler) => handler is ExecutionDomainHandler,
- orElse: () => null);
- Set<ExecutionService> services = new Set<ExecutionService>();
- if (handler.onFileAnalyzed != null) {
- services.add(ExecutionService.LAUNCH_DATA);
- }
-
- if (handler != null) {
- buffer.write('<h3>Execution Domain</h3>');
- _writeTwoColumns(buffer, (StringBuffer buffer) {
- _writeSubscriptionList(buffer, ExecutionService.VALUES, services);
- }, (StringBuffer buffer) {});
- }
- }
-
- /**
- * Write a representation of an analysis option with the given [name] and
- * [value] to the given [buffer]. The option should be separated from other
- * options unless the [last] flag is true, indicating that this is the last
- * option in the list of options.
- */
- void _writeOption(StringBuffer buffer, String name, Object value,
- {bool last: false}) {
- buffer.write(name);
- buffer.write(' = ');
- buffer.write(value.toString());
- if (!last) {
- buffer.write('<br>');
- }
- }
-
- /**
- * Write a standard HTML page to the given [buffer]. The page will have the
- * given [title] and a body that is generated by the given [body] generator.
- */
- void _writePage(StringBuffer buffer, String title, List<String> subtitles,
- HtmlGenerator body) {
- DateTime now = new DateTime.now();
- String date = "${now.month}/${now.day}/${now.year}";
- String time =
- "${now.hour}:${_twoDigit(now.minute)}:${_twoDigit(now.second)}.${now.millisecond}";
-
- buffer.write('<!DOCTYPE html>');
- buffer.write('<html>');
- buffer.write('<head>');
- buffer.write('<meta charset="utf-8">');
- buffer.write(
- '<meta name="viewport" content="width=device-width, initial-scale=1.0">');
- buffer.write('<title>$title</title>');
- buffer.write('<style>');
- buffer.write('a {color: #0000DD; text-decoration: none;}');
- buffer.write('a:link.error {background-color: #FFEEEE;}');
- buffer.write('a:visited.error {background-color: #FFEEEE;}');
- buffer.write('a:hover.error {background-color: #FFEEEE;}');
- buffer.write('a:active.error {background-color: #FFEEEE;}');
- buffer.write(
- 'h3 {background-color: #DDDDDD; margin-top: 0em; margin-bottom: 0em;}');
- buffer.write('p {margin-top: 0.5em; margin-bottom: 0.5em;}');
-// response.write('span.error {text-decoration-line: underline; text-decoration-color: red; text-decoration-style: wavy;}');
- buffer.write(
- 'table.column {border: 0px solid black; width: 100%; table-layout: fixed;}');
- buffer.write('td.column {vertical-align: top; width: 50%;}');
- buffer.write('td.right {text-align: right;}');
- buffer.write('</style>');
- buffer.write('</head>');
-
- buffer.write('<body>');
- buffer.write(
- '<h2>$title <small><small>(as of $time on $date)</small></small></h2>');
- if (subtitles != null && subtitles.isNotEmpty) {
- buffer.write('<blockquote>');
- bool first = true;
- for (String subtitle in subtitles) {
- if (first) {
- first = false;
- } else {
- buffer.write('<br>');
- }
- buffer.write('<b>');
- buffer.write(subtitle);
- buffer.write('</b>');
- }
- buffer.write('</blockquote>');
- }
- try {
- body(buffer);
- } catch (exception, stackTrace) {
- buffer.write('<h3>Exception while creating page</h3>');
- _writeException(buffer, new CaughtException(exception, stackTrace));
- }
- buffer.write('</body>');
- buffer.write('</html>');
- }
-
- /**
- * Write the recent output section (on the main status page) to the given
- * [buffer] object.
- */
- void _writePluginStatus(StringBuffer buffer) {
- void writePlugin(Plugin plugin) {
- buffer.write(plugin.uniqueIdentifier);
- buffer.write(' (');
- buffer.write(plugin.runtimeType);
- buffer.write(')<br>');
- }
- buffer.write('<h3>Plugin Status</h3><p>');
- writePlugin(AnalysisEngine.instance.enginePlugin);
- writePlugin(_server.serverPlugin);
- for (Plugin plugin in _server.analysisServer.userDefinedPlugins) {
- writePlugin(plugin);
- }
- buffer.write('<p>');
- }
-
- /**
- * Write the recent output section (on the main status page) to the given
- * [buffer] object.
- */
- void _writeRecentOutput(StringBuffer buffer) {
- buffer.write('<h3>Recent Output</h3>');
- String output = HTML_ESCAPE.convert(_printBuffer.join('\n'));
- if (output.isEmpty) {
- buffer.write('<i>none</i>');
- } else {
- buffer.write('<pre>');
- buffer.write(output);
- buffer.write('</pre>');
- }
- }
-
- void _writeResponse(HttpRequest request, HtmlGenerator writePage) {
- HttpResponse response = request.response;
- response.statusCode = HttpStatus.OK;
- response.headers.contentType = _htmlContent;
- try {
- StringBuffer buffer = new StringBuffer();
- try {
- writePage(buffer);
- } catch (exception, stackTrace) {
- buffer.clear();
- _writePage(buffer, 'Internal Exception', [], (StringBuffer buffer) {
- _writeException(buffer, new CaughtException(exception, stackTrace));
- });
- }
- response.write(buffer.toString());
- } finally {
- response.close();
- }
- }
-
- /**
- * Write a single row within a table to the given [buffer]. The row will have
- * one cell for each of the [columns], and will be a header row if [header] is
- * `true`.
- */
- void _writeRow(StringBuffer buffer, List<Object> columns,
- {bool header: false, List<String> classes}) {
- buffer.write('<tr>');
- int count = columns.length;
- int maxClassIndex = classes == null ? 0 : classes.length - 1;
- for (int i = 0; i < count; i++) {
- String classAttribute = '';
- if (classes != null) {
- String className = classes[min(i, maxClassIndex)];
- if (className != null) {
- classAttribute = ' class="$className"';
- }
- }
- if (header) {
- buffer.write('<th$classAttribute>');
- } else {
- buffer.write('<td$classAttribute>');
- }
- buffer.write(columns[i]);
- if (header) {
- buffer.write('</th>');
- } else {
- buffer.write('</td>');
- }
- }
- buffer.write('</tr>');
- }
-
- /**
- * Write the status of the service domain (on the main status page) to the
- * given [response] object.
- */
- bool _writeServerStatus(StringBuffer buffer) {
- AnalysisServer analysisServer = _server.analysisServer;
- Set<ServerService> services = analysisServer.serverServices;
-
- buffer.write('<h3>Server Domain</h3>');
- _writeTwoColumns(buffer, (StringBuffer buffer) {
- if (analysisServer == null) {
- buffer.write('Status: <span style="color:red">Not running</span>');
- return false;
- }
- buffer.write('<p>');
- buffer.write('Status: Running<br>');
- buffer.write('Instrumentation: ');
- if (AnalysisEngine.instance.instrumentationService.isActive) {
- buffer.write('<span style="color:red">Active</span>');
- } else {
- buffer.write('Inactive');
- }
- buffer.write('<br>');
- buffer.write('Version: ');
- buffer.write(AnalysisServer.VERSION);
- buffer.write('</p>');
-
- buffer.write('<p><b>Performance Data</b></p>');
- buffer.write('<p>');
- buffer.write(makeLink(
- COMMUNICATION_PERFORMANCE_PATH, {}, 'Communication performance'));
- buffer.write('</p>');
- }, (StringBuffer buffer) {
- _writeSubscriptionList(buffer, ServerService.VALUES, services);
- });
- return true;
- }
-
- /**
- * Write a representation of the given [stackTrace] to the given [buffer].
- */
- void _writeStackTrace(StringBuffer buffer, StackTrace stackTrace) {
- if (stackTrace != null) {
- String trace = stackTrace.toString().replaceAll('#', '<br>#');
- if (trace.startsWith('<br>#')) {
- trace = trace.substring(4);
- }
- buffer.write('<p>');
- buffer.write(trace);
- buffer.write('</p>');
- }
- }
-
- /**
- * Given a [service] that could be subscribed to and a set of the services
- * that are actually subscribed to ([subscribedServices]), write a
- * representation of the service to the given [buffer].
- */
- void _writeSubscriptionInList(
- StringBuffer buffer, Enum service, Set<Enum> subscribedServices) {
- if (subscribedServices.contains(service)) {
- buffer.write('<code>+ </code>');
- } else {
- buffer.write('<code>- </code>');
- }
- buffer.write(service.name);
- buffer.write('<br>');
- }
-
- /**
- * Given a [service] that could be subscribed to and a set of paths that are
- * subscribed to the services ([subscribedPaths]), write a representation of
- * the service to the given [buffer].
- */
- void _writeSubscriptionInMap(
- StringBuffer buffer, Enum service, Set<String> subscribedPaths) {
- buffer.write('<p>');
- buffer.write(service.name);
- buffer.write('</p>');
- if (subscribedPaths == null || subscribedPaths.isEmpty) {
- buffer.write('none');
- } else {
- List<String> paths = subscribedPaths.toList();
- paths.sort();
- for (String path in paths) {
- buffer.write('<p>');
- buffer.write(path);
- buffer.write('</p>');
- }
- }
- }
-
- /**
- * Given a list containing all of the services that can be subscribed to in a
- * single domain ([allServices]) and a set of the services that are actually
- * subscribed to ([subscribedServices]), write a representation of the
- * subscriptions to the given [buffer].
- */
- void _writeSubscriptionList(StringBuffer buffer, List<Enum> allServices,
- Set<Enum> subscribedServices) {
- buffer.write('<p><b>Subscriptions</b></p>');
- buffer.write('<p>');
- for (Enum service in allServices) {
- _writeSubscriptionInList(buffer, service, subscribedServices);
- }
- buffer.write('</p>');
- }
-
- /**
- * Given a list containing all of the services that can be subscribed to in a
- * single domain ([allServices]) and a set of the services that are actually
- * subscribed to ([subscribedServices]), write a representation of the
- * subscriptions to the given [buffer].
- */
- void _writeSubscriptionMap(StringBuffer buffer, List<Enum> allServices,
- Map<Enum, Set<String>> subscribedServices) {
- buffer.write('<p><b>Subscriptions</b></p>');
- for (Enum service in allServices) {
- _writeSubscriptionInMap(buffer, service, subscribedServices[service]);
- }
- }
-
- /**
- * Write two columns of information to the given [buffer], where the
- * [leftColumn] and [rightColumn] functions are used to generate the content
- * of those columns.
- */
- void _writeTwoColumns(StringBuffer buffer, HtmlGenerator leftColumn,
- HtmlGenerator rightColumn) {
- buffer
- .write('<table class="column"><tr class="column"><td class="column">');
- leftColumn(buffer);
- buffer.write('</td><td class="column">');
- rightColumn(buffer);
- buffer.write('</td></tr></table>');
- }
-
- /**
- * Render the given [value] as HTML and append it to the given [buffer]. The
- * [linkParameters] will be used if the value is too large to be displayed on
- * the current page and needs to be linked to a separate page.
- */
- void _writeValueAsHtml(
- StringBuffer buffer, Object value, Map<String, String> linkParameters) {
- if (value == null) {
- buffer.write('<i>null</i>');
- } else if (value is String) {
- buffer.write('<pre>${HTML_ESCAPE.convert(value)}</pre>');
- } else if (value is List) {
- buffer.write('List containing ${value.length} entries');
- buffer.write('<ul>');
- for (var entry in value) {
- buffer.write('<li>');
- _writeValueAsHtml(buffer, entry, linkParameters);
- buffer.write('</li>');
- }
- buffer.write('</ul>');
- } else if (value is AstNode) {
- String link =
- makeLink(AST_PATH, linkParameters, value.runtimeType.toString());
- buffer.write('<i>$link</i>');
- } else if (value is Element) {
- String link =
- makeLink(ELEMENT_PATH, linkParameters, value.runtimeType.toString());
- buffer.write('<i>$link</i>');
- } else {
- buffer.write(HTML_ESCAPE.convert(value.toString()));
- buffer.write(' <i>(${value.runtimeType.toString()})</i>');
- }
- }
-
- /**
- * Create a link to [path] with query parameters [params], with inner HTML
- * [innerHtml]. If [hasError] is `true`, then the link will have the class
- * 'error'.
- */
- static String makeLink(
- String path, Map<String, String> params, String innerHtml,
- [bool hasError = false]) {
- Uri uri = new Uri(path: path, queryParameters: params);
- String href = HTML_ESCAPE.convert(uri.toString());
- String classAttribute = hasError ? ' class="error"' : '';
- return '<a href="$href"$classAttribute>$innerHtml</a>';
- }
-}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index aeb8d03..66fac73 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -21,7 +21,6 @@
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/html.dart';
import 'package:analyzer/src/generated/source.dart';
/**
@@ -152,14 +151,18 @@
});
}
-void sendAnalysisNotificationErrors(AnalysisServer server, String file,
- LineInfo lineInfo, List<AnalysisError> errors) {
+void sendAnalysisNotificationErrors(
+ AnalysisServer server,
+ AnalysisContext context,
+ String file,
+ LineInfo lineInfo,
+ List<AnalysisError> errors) {
_sendNotification(server, () {
if (errors == null) {
errors = <AnalysisError>[];
}
var serverErrors =
- protocol.doAnalysisError_listFromEngine(lineInfo, errors);
+ protocol.doAnalysisError_listFromEngine(context, lineInfo, errors);
var params = new protocol.AnalysisErrorsParams(file, serverErrors);
server.sendNotification(params.toNotification());
});
@@ -422,16 +425,6 @@
server.sendServerErrorNotification(
'Failed to index Dart file: $file', exception, stackTrace);
}
- // HTML
- try {
- HtmlUnit htmlUnit = notice.resolvedHtmlUnit;
- if (htmlUnit != null) {
- server.addOperation(new _HtmlIndexOperation(context, file, htmlUnit));
- }
- } catch (exception, stackTrace) {
- server.sendServerErrorNotification(
- 'Failed to index HTML file: $file', exception, stackTrace);
- }
}
}
}
@@ -510,24 +503,6 @@
}
}
-class _HtmlIndexOperation extends _SingleFileOperation {
- final HtmlUnit unit;
-
- _HtmlIndexOperation(AnalysisContext context, String file, this.unit)
- : super(context, file);
-
- @override
- ServerOperationPriority get priority {
- return ServerOperationPriority.ANALYSIS_INDEX;
- }
-
- @override
- void perform(AnalysisServer server) {
- Index index = server.index;
- index.index(context, unit);
- }
-}
-
class _NotificationErrorsOperation extends _SingleFileOperation {
final LineInfo lineInfo;
final List<AnalysisError> errors;
@@ -543,7 +518,7 @@
@override
void perform(AnalysisServer server) {
- sendAnalysisNotificationErrors(server, file, lineInfo, errors);
+ sendAnalysisNotificationErrors(server, context, file, lineInfo, errors);
}
}
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index 678361f..981b694 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -9,6 +9,7 @@
import 'package:analysis_server/src/services/correction/fix.dart';
import 'package:analysis_server/src/services/search/search_engine.dart'
as engine;
+import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/generated/ast.dart' as engine;
import 'package:analyzer/src/generated/element.dart' as engine;
import 'package:analyzer/src/generated/engine.dart' as engine;
@@ -20,14 +21,29 @@
export 'package:analysis_server/plugin/protocol/protocol_dart.dart';
/**
- * Returns a list of AnalysisErrors correponding to the given list of Engine
+ * Returns a list of AnalysisErrors corresponding to the given list of Engine
* errors.
*/
List<AnalysisError> doAnalysisError_listFromEngine(
- engine.LineInfo lineInfo, List<engine.AnalysisError> errors) {
- return errors.map((engine.AnalysisError error) {
- return newAnalysisError_fromEngine(lineInfo, error);
- }).toList();
+ engine.AnalysisContext context,
+ engine.LineInfo lineInfo,
+ List<engine.AnalysisError> errors) {
+ List<AnalysisError> serverErrors = <AnalysisError>[];
+ for (engine.AnalysisError error in errors) {
+ ErrorProcessor processor = ErrorProcessor.getProcessor(context, error);
+ if (processor != null) {
+ engine.ErrorSeverity severity = processor.severity;
+ // Errors with null severity are filtered out.
+ if (severity != null) {
+ // Specified severities override.
+ serverErrors
+ .add(newAnalysisError_fromEngine(lineInfo, error, severity));
+ }
+ } else {
+ serverErrors.add(newAnalysisError_fromEngine(lineInfo, error));
+ }
+ }
+ return serverErrors;
}
/**
@@ -55,7 +71,7 @@
if (element.kind == engine.ElementKind.SETTER) {
return null;
} else {
- return element.returnType.toString();
+ return element.returnType?.toString();
}
} else if (element is engine.VariableElement) {
engine.DartType type = element.type;
@@ -69,9 +85,12 @@
/**
* Construct based on error information from the analyzer engine.
+ *
+ * If an [errorSeverity] is specified, it will override the one in [error].
*/
AnalysisError newAnalysisError_fromEngine(
- engine.LineInfo lineInfo, engine.AnalysisError error) {
+ engine.LineInfo lineInfo, engine.AnalysisError error,
+ [engine.ErrorSeverity errorSeverity]) {
engine.ErrorCode errorCode = error.errorCode;
// prepare location
Location location;
@@ -90,8 +109,12 @@
}
location = new Location(file, offset, length, startLine, startColumn);
}
+
+ // Deafult to the error's severity if none is specified.
+ errorSeverity ??= errorCode.errorSeverity;
+
// done
- var severity = new AnalysisErrorSeverity(errorCode.errorSeverity.name);
+ var severity = new AnalysisErrorSeverity(errorSeverity.name);
var type = new AnalysisErrorType(errorCode.type.name);
String message = error.message;
String correction = error.correction;
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
index 816894d..827024b 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_dart.dart
@@ -10,6 +10,8 @@
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/element.dart';
+import 'package:analyzer/src/generated/source.dart';
export 'package:analysis_server/src/provisional/completion/completion_core.dart'
show EMPTY_LIST;
@@ -60,27 +62,61 @@
*/
abstract class DartCompletionRequest extends CompletionRequest {
/**
+ * Return the expression to the right of the "dot" or "dot dot",
+ * or `null` if this is not a "dot" completion (e.g. `foo.b`).
+ */
+ Expression get dotTarget;
+
+ /**
+ * Return `true` if free standing identifiers should be suggested
+ */
+ bool get includeIdentifiers;
+
+ /**
+ * Return the library element which contains the unit in which the completion
+ * is occurring. This may return `null` if the library cannot be determined
+ * (e.g. unlinked part file).
+ */
+ LibraryElement get libraryElement;
+
+ /**
+ * The source for the library containing the completion request.
+ * This may be different from the source in which the completion is requested
+ * if the completion is being requested in a part file.
+ * This may be `null` if the library for a part file cannot be determined.
+ */
+ Source get librarySource;
+
+ /**
+ * Answer the [DartType] for Object in dart:core
+ */
+ DartType get objectType;
+
+ /**
* Return the completion target. This determines what part of the parse tree
* will receive the newly inserted text.
+ * At a minimum, all declarations in the completion scope in [target.unit]
+ * will be resolved if they can be resolved.
*/
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
+ * Return a [Future] that completes with a list of directives for the library
+ * in which in which the completion is occurring.
+ * The [Future] may return `null` if the library unit cannot be determined
* (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();
+ Future<List<Directive>> resolveDirectives();
/**
* Return a [Future] that completes when the element associated with
- * the given [identifier] is available or if the identifier cannot be resolved
+ * the given [expression] in the target compilation unit is available.
+ * It may also complete if the expression 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);
+ Future resolveExpression(Expression expression);
}
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
index 014c270..64fecef 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_plugin.dart
@@ -12,6 +12,11 @@
import 'package:analysis_server/src/services/completion/dart/completion_manager.dart';
import 'package:analysis_server/src/services/completion/dart/field_formal_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/keyword_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/library_prefix_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/named_constructor_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/static_member_contributor.dart';
+import 'package:analysis_server/src/services/completion/dart/type_member_contributor.dart';
import 'package:analysis_server/src/services/completion/dart/uri_contributor.dart';
import 'package:plugin/plugin.dart';
@@ -77,6 +82,16 @@
registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
() => new KeywordContributor());
registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new LibraryMemberContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new LibraryPrefixContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new NamedConstructorContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new StaticMemberContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
+ () => new TypeMemberContributor());
+ registerExtension(DART_COMPLETION_CONTRIBUTOR_EXTENSION_POINT_ID,
() => new UriContributor());
}
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 0cb0035..7762e9e 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
@@ -91,6 +91,11 @@
final CompilationUnit unit;
/**
+ * The offset within the source at which the completion is being requested.
+ */
+ final int offset;
+
+ /**
* The context in which the completion is occurring. This is the AST node
* which is a direct parent of [entity].
*/
@@ -162,11 +167,11 @@
Token commentToken = _getContainingCommentToken(entity, offset);
if (commentToken != null) {
return new CompletionTarget._(
- compilationUnit, containingNode, commentToken, true);
+ compilationUnit, offset, containingNode, commentToken, true);
}
// Target found.
return new CompletionTarget._(
- compilationUnit, containingNode, entity, false);
+ compilationUnit, offset, containingNode, entity, false);
} else {
// Since entity is a token, we don't need to look inside it; just
// proceed to the next entity.
@@ -195,12 +200,12 @@
if (docComment != null) {
containingNode = docComment;
} else {
- return new CompletionTarget._(
- compilationUnit, compilationUnit, commentToken, true);
+ return new CompletionTarget._(compilationUnit, offset,
+ compilationUnit, commentToken, true);
}
}
return new CompletionTarget._(
- compilationUnit, containingNode, entity, false);
+ compilationUnit, offset, containingNode, entity, false);
}
// Otherwise, the completion target is somewhere inside the entity,
@@ -225,7 +230,7 @@
// 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, compilationUnit, null, false);
+ compilationUnit, offset, compilationUnit, null, false);
}
}
@@ -233,13 +238,30 @@
* Create a [CompletionTarget] holding the given [containingNode] and
* [entity].
*/
- CompletionTarget._(
- this.unit, AstNode containingNode, Object entity, this.isCommentText)
+ CompletionTarget._(this.unit, this.offset, AstNode containingNode,
+ Object entity, this.isCommentText)
: this.containingNode = containingNode,
this.entity = entity,
this.argIndex = _computeArgIndex(containingNode, entity);
/**
+ * Return `true` if the [containingNode] is a cascade
+ * and the completion insertion is not between the two dots.
+ * For example, `..d^` and `..^d` are considered a cascade
+ * from a completion standpoint, but `.^.d` is not.
+ */
+ bool get isCascade {
+ AstNode node = containingNode;
+ if (node is PropertyAccess) {
+ return node.isCascaded && offset > node.operator.offset + 1;
+ }
+ if (node is MethodInvocation) {
+ return node.isCascaded && offset > node.operator.offset + 1;
+ }
+ return false;
+ }
+
+ /**
* Return `true` if the target is a functional argument in an argument list.
* The target [AstNode] hierarchy *must* be resolved for this to work.
*/
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 27fb203..5833af4 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -27,6 +27,7 @@
import 'package:analyzer/src/generated/sdk_io.dart';
import 'package:args/args.dart';
import 'package:linter/src/plugin/linter_plugin.dart';
+import 'package:plugin/manager.dart';
import 'package:plugin/plugin.dart';
/**
@@ -208,11 +209,6 @@
static const String CLIENT_VERSION = "client-version";
/**
- * The name of the option used to disable the use of the new task model.
- */
- static const String DISABLE_NEW_TASK_MODEL = "disable-new-task-model";
-
- /**
* The name of the option used to enable incremental resolution of API
* changes.
*/
@@ -398,25 +394,21 @@
results[CLIENT_VERSION], AnalysisServer.VERSION, defaultSdk.sdkVersion);
AnalysisEngine.instance.instrumentationService = service;
//
- // Enable the new task model, if appropriate.
- //
- AnalysisEngine.instance.useTaskModel = !results[DISABLE_NEW_TASK_MODEL];
- //
// Process all of the plugins so that extensions are registered.
//
ServerPlugin serverPlugin = new ServerPlugin();
List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
plugins.add(serverPlugin);
- plugins.addAll(_userDefinedPlugins);
plugins.add(linterPlugin);
plugins.add(linterServerPlugin);
plugins.add(dartCompletionPlugin);
+ plugins.addAll(_userDefinedPlugins);
- // Defer to the extension manager in AE for plugin registration.
- AnalysisEngine.instance.userDefinedPlugins = plugins;
- // Force registration.
- AnalysisEngine.instance.taskManager;
-
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
//
// Create the sockets and start listening for requests.
//
@@ -480,11 +472,6 @@
parser.addOption(CLIENT_ID,
help: "an identifier used to identify the client");
parser.addOption(CLIENT_VERSION, help: "the version of the client");
- parser.addFlag(DISABLE_NEW_TASK_MODEL,
- help: "disable the use of the new task model",
- defaultsTo: false,
- hide: true,
- negatable: false);
parser.addFlag(ENABLE_INCREMENTAL_RESOLUTION_API,
help: "enable using incremental resolution for API changes",
defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/server/http_server.dart b/pkg/analysis_server/lib/src/server/http_server.dart
index c047d1f..9afabda 100644
--- a/pkg/analysis_server/lib/src/server/http_server.dart
+++ b/pkg/analysis_server/lib/src/server/http_server.dart
@@ -2,16 +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.
-library http.server;
+library analysis_server.src.server.http_server;
import 'dart:async';
import 'dart:io';
import 'package:analysis_server/src/channel/web_socket_channel.dart';
-import 'package:analysis_server/src/get_handler.dart';
import 'package:analysis_server/src/socket_server.dart';
-import 'package:analysis_server/src/status/get_handler.dart' as newHandler;
-import 'package:analyzer/src/generated/engine.dart';
+import 'package:analysis_server/src/status/get_handler.dart';
/**
* Instances of the class [HttpServer] implement a simple HTTP server. The
@@ -36,11 +34,6 @@
GetHandler getHandler;
/**
- * An object that can handle GET requests when the new task model is in use.
- */
- newHandler.GetHandler newGetHandler;
-
- /**
* Future that is completed with the HTTP server once it is running.
*/
Future<HttpServer> _server;
@@ -89,17 +82,10 @@
* Handle a GET request received by the HTTP server.
*/
void _handleGetRequest(HttpRequest request) {
- if (AnalysisEngine.instance.useTaskModel) {
- if (newGetHandler == null) {
- newGetHandler = new newHandler.GetHandler(socketServer, _printBuffer);
- }
- newGetHandler.handleGetRequest(request);
- } else {
- if (getHandler == null) {
- getHandler = new GetHandler(socketServer, _printBuffer);
- }
- getHandler.handleGetRequest(request);
+ if (getHandler == null) {
+ getHandler = new GetHandler(socketServer, _printBuffer);
}
+ getHandler.handleGetRequest(request);
}
/**
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
index 46e20aa..29f463b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -87,6 +87,23 @@
}
/**
+ * Determine if the completion target is the label for a named argument.
+ */
+bool _isEditingNamedArgLabel(DartCompletionRequest request) {
+ AstNode node = request.target.containingNode;
+ if (node is ArgumentList) {
+ var entity = request.target.entity;
+ if (entity is NamedExpression) {
+ int offset = request.offset;
+ if (entity.offset <= offset && offset < entity.end) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+/**
* Determine if the completion target is an emtpy argument list.
*/
bool _isEmptyArgList(DartCompletionRequest request) {
@@ -134,7 +151,7 @@
}
// Resolve the target expression to determine the arguments
- await request.resolveIdentifier(targetId);
+ await request.resolveExpression(targetId);
// Gracefully degrade if the element could not be resolved
// e.g. target changed, completion aborted
targetId = _getTargetId(request.target.containingNode);
@@ -171,32 +188,35 @@
}
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);
+ // DEPRECATED... argument lists are no longer suggested.
+ // See https://github.com/dart-lang/sdk/issues/25197
+
+ // 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) {
@@ -233,7 +253,7 @@
_addArgListSuggestion(requiredParam);
return;
}
- if (_isAppendingToArgList(request)) {
+ if (_isEditingNamedArgLabel(request) || _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
index cba3bd4..a08b8bb 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/combinator_contributor.dart
@@ -26,20 +26,6 @@
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) {
@@ -47,7 +33,7 @@
if (library != null) {
LibraryElementSuggestionBuilder builder =
new LibraryElementSuggestionBuilder(
- request, CompletionSuggestionKind.IDENTIFIER, false, false);
+ library, CompletionSuggestionKind.IDENTIFIER, false, false);
library.visitChildren(builder);
return builder.suggestions;
}
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 6f182d8..a635b8c 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
@@ -18,10 +18,12 @@
import 'package:analyzer/src/context/context.dart'
show AnalysisFutureHelper, AnalysisContextImpl;
import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.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';
+import 'package:analysis_server/src/services/completion/optype.dart';
/**
* [DartCompletionManager] determines if a completion request is Dart specific
@@ -30,24 +32,17 @@
class DartCompletionManager implements CompletionContributor {
@override
Future<List<CompletionSuggestion>> computeSuggestions(
- CompletionRequest request) {
- if (AnalysisEngine.isDartFileName(request.source.shortName)) {
- return _computeDartSuggestions(
- new DartCompletionRequestImpl.forRequest(request));
+ CompletionRequest request) async {
+ if (!AnalysisEngine.isDartFileName(request.source.shortName)) {
+ return EMPTY_LIST;
}
- 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
+ DartCompletionRequestImpl dartRequest =
+ await DartCompletionRequestImpl.from(request);
List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
for (DartCompletionContributor c in dartCompletionPlugin.contributors) {
- suggestions.addAll(await c.computeSuggestions(request));
+ suggestions.addAll(await c.computeSuggestions(dartRequest));
}
return suggestions;
}
@@ -59,115 +54,139 @@
class DartCompletionRequestImpl extends CompletionRequestImpl
implements DartCompletionRequest {
/**
- * The cached completion target or `null` if not computed yet.
+ * Return a [Future] that completes with a newly created completion request
+ * based on the given [request].
*/
- CompletionTarget _target;
+ static Future<DartCompletionRequest> from(CompletionRequest request) async {
+ Source source = request.source;
+ AnalysisContext context = request.context;
+ CompilationUnit unit = request.context.computeResult(source, PARSED_UNIT);
- /**
- * `true` if [resolveDeclarationsInScope] has partially resolved the unit
- * referenced by [target], else `false`.
- */
- bool _haveResolveDeclarationsInScope = false;
+ Source libSource;
+ if (unit.directives.any((d) => d is PartOfDirective)) {
+ List<Source> libraries = context.getLibrariesContaining(source);
+ if (libraries.isNotEmpty) {
+ libSource = libraries[0];
+ }
+ } else {
+ libSource = source;
+ }
- /**
- * Initialize a newly created completion request based on the given request.
- */
- factory DartCompletionRequestImpl.forRequest(CompletionRequest request) {
+ // Most (all?) contributors need declarations in scope to be resolved
+ if (libSource != null) {
+ unit = await new AnalysisFutureHelper<CompilationUnit>(context,
+ new LibrarySpecificUnit(libSource, source), RESOLVED_UNIT3)
+ .computeAsync();
+ }
+
return new DartCompletionRequestImpl._(
request.context,
request.resourceProvider,
request.searchEngine,
+ libSource,
request.source,
- request.offset);
+ request.offset,
+ unit);
}
DartCompletionRequestImpl._(
AnalysisContext context,
ResourceProvider resourceProvider,
SearchEngine searchEngine,
+ this.librarySource,
Source source,
- int offset)
- : super(context, resourceProvider, searchEngine, source, offset);
+ int offset,
+ CompilationUnit unit)
+ : super(context, resourceProvider, searchEngine, source, offset) {
+ _updateTargets(unit);
+ }
+
+ /**
+ * The [DartType] for Object in dart:core
+ */
+ InterfaceType _objectType;
@override
- CompletionTarget get target {
- if (_target == null) {
- CompilationUnit unit = context.computeResult(source, PARSED_UNIT);
- _target = new CompletionTarget.forOffset(unit, offset);
+ Expression dotTarget;
+
+ @override
+ Source librarySource;
+
+ OpType _opType;
+
+ @override
+ CompletionTarget target;
+
+ @override
+ bool get includeIdentifiers {
+ if (_opType == null) {
+ _opType = new OpType.forCompletion(target, offset);
}
- return _target;
+ return !_opType.isPrefixed &&
+ (_opType.includeReturnValueSuggestions ||
+ _opType.includeTypeNameSuggestions ||
+ _opType.includeVoidReturnSuggestions ||
+ _opType.includeConstructorSuggestions);
}
@override
- Future<CompilationUnit> resolveDeclarationsInScope() async {
+ LibraryElement get libraryElement {
+ //TODO(danrubel) build the library element rather than all the declarations
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;
+ if (unit != null) {
+ CompilationUnitElement elem = unit.element;
+ if (elem != null) {
+ return elem.library;
}
- 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;
+ return null;
}
@override
- Future resolveIdentifier(SimpleIdentifier identifier) async {
- if (identifier.bestElement != null) {
+ InterfaceType get objectType {
+ if (_objectType == null) {
+ Source coreUri = context.sourceFactory.forUri('dart:core');
+ LibraryElement coreLib = context.getLibraryElement(coreUri);
+ _objectType = coreLib.getType('Object').type;
+ }
+ return _objectType;
+ }
+
+ @override
+ Future<List<Directive>> resolveDirectives() async {
+ CompilationUnit libUnit;
+ if (librarySource == source) {
+ libUnit = target.unit;
+ } else if (librarySource != null) {
+ // TODO(danrubel) only resolve the directives
+ libUnit = await new AnalysisFutureHelper<CompilationUnit>(
+ context,
+ new LibrarySpecificUnit(librarySource, librarySource),
+ RESOLVED_UNIT3)
+ .computeAsync();
+ }
+ return libUnit?.directives;
+ }
+
+ @override
+ Future resolveExpression(Expression expression) async {
+ // Return immediately if the expression has already been resolved
+ if (expression.propagatedType != null) {
return;
}
- //TODO(danrubel) resolve the expression or containing method
+ // Gracefully degrade if librarySource cannot be determined
+ if (librarySource == null) {
+ return;
+ }
+
+ // Resolve declarations in the target unit
+ // 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();
+ 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
@@ -179,7 +198,35 @@
}
// Recompute the target for the newly resolved unit
- _target = new CompletionTarget.forOffset(resolvedUnit, offset);
- _haveResolveDeclarationsInScope = true;
+ _updateTargets(resolvedUnit);
+ }
+
+ /**
+ * Update the completion [target] and [dotTarget] based on the given [unit].
+ */
+ void _updateTargets(CompilationUnit unit) {
+ _opType = null;
+ dotTarget = null;
+ target = new CompletionTarget.forOffset(unit, offset);
+ AstNode node = target.containingNode;
+ if (node is MethodInvocation) {
+ if (identical(node.methodName, target.entity)) {
+ dotTarget = node.realTarget;
+ } else if (node.isCascaded && node.operator.offset + 1 == target.offset) {
+ dotTarget = node.realTarget;
+ }
+ }
+ if (node is PropertyAccess) {
+ if (identical(node.propertyName, target.entity)) {
+ dotTarget = node.realTarget;
+ } else if (node.isCascaded && node.operator.offset + 1 == target.offset) {
+ dotTarget = node.realTarget;
+ }
+ }
+ if (node is PrefixedIdentifier) {
+ if (identical(node.identifier, target.entity)) {
+ dotTarget = node.prefix;
+ }
+ }
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
index f708685..3c16a7d 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/field_formal_contributor.dart
@@ -20,19 +20,6 @@
@override
Future<List<CompletionSuggestion>> computeSuggestions(
DartCompletionRequest request) async {
- if (request.target.containingNode is! FieldFormalParameter) {
- 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
AstNode node = request.target.containingNode;
if (node is! FieldFormalParameter) {
return EMPTY_LIST;
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
index fdfb353..2ab41e3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/inherited_contributor.dart
@@ -26,26 +26,10 @@
@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) {
@@ -65,7 +49,7 @@
// Gracefully degrade if the overridden element has not been resolved.
if (element.returnType != null) {
CompletionSuggestion suggestion =
- _buildSuggestion(request, targetId, unit, element);
+ _buildSuggestion(request, targetId, element);
if (suggestion != null) {
suggestions.add(suggestion);
}
@@ -119,13 +103,10 @@
* 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);
+ CompletionSuggestion _buildSuggestion(DartCompletionRequest request,
+ SimpleIdentifier targetId, ExecutableElement element) {
+ String completion = _buildRepacementText(
+ request.source, targetId, request.target.unit, element);
if (completion == null || completion.length == 0) {
return null;
}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
index 57beb27..28de09b 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/keyword_contributor.dart
@@ -13,7 +13,11 @@
import 'package:analyzer/src/generated/scanner.dart';
const ASYNC = 'async';
+const ASYNC_STAR = 'async*';
const AWAIT = 'await';
+const SYNC_STAR = 'sync*';
+const YIELD = 'yield';
+const YIELD_STAR = 'yield*';
/**
* A contributor for calculating `completion.getSuggestions` request results
@@ -47,8 +51,19 @@
@override
visitArgumentList(ArgumentList node) {
- if (entity == node.rightParenthesis ||
- (entity is SimpleIdentifier && node.arguments.contains(entity))) {
+ if (entity == node.rightParenthesis) {
+ _addExpressionKeywords(node);
+ Token previous = (entity as Token).previous;
+ if (previous.isSynthetic) {
+ previous = previous.previous;
+ }
+ if (previous.lexeme == ')') {
+ _addSuggestion2(ASYNC);
+ _addSuggestion2(ASYNC_STAR);
+ _addSuggestion2(SYNC_STAR);
+ }
+ }
+ if (entity is SimpleIdentifier && node.arguments.contains(entity)) {
_addExpressionKeywords(node);
}
}
@@ -69,6 +84,8 @@
}
if (previous.lexeme == ')' && next.lexeme == '{') {
_addSuggestion2(ASYNC);
+ _addSuggestion2(ASYNC_STAR);
+ _addSuggestion2(SYNC_STAR);
}
}
}
@@ -92,6 +109,8 @@
ClassMember previous = index > 0 ? node.members[index - 1] : null;
if (previous is MethodDeclaration && previous.body is EmptyFunctionBody) {
_addSuggestion2(ASYNC);
+ _addSuggestion2(ASYNC_STAR);
+ _addSuggestion2(SYNC_STAR);
}
} else {
_addClassDeclarationKeywords(node);
@@ -138,6 +157,8 @@
previousMember.functionExpression is FunctionExpression &&
previousMember.functionExpression.body is EmptyFunctionBody) {
_addSuggestion2(ASYNC, relevance: DART_RELEVANCE_HIGH);
+ _addSuggestion2(ASYNC_STAR, relevance: DART_RELEVANCE_HIGH);
+ _addSuggestion2(SYNC_STAR, relevance: DART_RELEVANCE_HIGH);
}
_addCompilationUnitKeywords();
}
@@ -200,8 +221,13 @@
@override
visitFunctionExpression(FunctionExpression node) {
if (entity == node.body) {
- if (!node.body.isAsynchronous) {
+ FunctionBody body = node.body;
+ if (!body.isAsynchronous) {
_addSuggestion2(ASYNC, relevance: DART_RELEVANCE_HIGH);
+ if (body is! ExpressionFunctionBody) {
+ _addSuggestion2(ASYNC_STAR, relevance: DART_RELEVANCE_HIGH);
+ _addSuggestion2(SYNC_STAR, relevance: DART_RELEVANCE_HIGH);
+ }
}
if (node.body is EmptyFunctionBody &&
node.parent is FunctionDeclaration &&
@@ -266,8 +292,14 @@
if (node.body is EmptyFunctionBody) {
_addClassBodyKeywords();
_addSuggestion2(ASYNC);
+ _addSuggestion2(ASYNC_STAR);
+ _addSuggestion2(SYNC_STAR);
} else {
_addSuggestion2(ASYNC, relevance: DART_RELEVANCE_HIGH);
+ if (node.body is! ExpressionFunctionBody) {
+ _addSuggestion2(ASYNC_STAR, relevance: DART_RELEVANCE_HIGH);
+ _addSuggestion2(SYNC_STAR, relevance: DART_RELEVANCE_HIGH);
+ }
}
}
}
@@ -433,6 +465,10 @@
}
if (_inAsyncMethodOrFunction(node)) {
_addSuggestion2(AWAIT);
+ } else if (_inAsyncStarOrSyncStarMethodOrFunction(node)) {
+ _addSuggestion2(AWAIT);
+ _addSuggestion2(YIELD);
+ _addSuggestion2(YIELD_STAR);
}
if (_inLoop(node)) {
_addSuggestions([Keyword.BREAK, Keyword.CONTINUE]);
@@ -481,7 +517,12 @@
bool _inAsyncMethodOrFunction(AstNode node) {
FunctionBody body = node.getAncestor((n) => n is FunctionBody);
- return body != null && body.isAsynchronous;
+ return body != null && body.isAsynchronous && body.star == null;
+ }
+
+ bool _inAsyncStarOrSyncStarMethodOrFunction(AstNode node) {
+ FunctionBody body = node.getAncestor((n) => n is FunctionBody);
+ return body != null && body.keyword != null && body.star != null;
}
bool _inCatchClause(Block node) =>
@@ -506,7 +547,7 @@
bool _inForLoop(AstNode node) =>
node.getAncestor((p) => p is ForStatement || p is ForEachStatement) !=
- null;
+ null;
bool _inLoop(AstNode node) =>
_inDoLoop(node) || _inForLoop(node) || _inWhileLoop(node);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
new file mode 100644
index 0000000..7ecbc64
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_member_contributor.dart
@@ -0,0 +1,90 @@
+// 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.library_member;
+
+import 'dart:async';
+
+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';
+
+import '../../../protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
+
+/**
+ * A contributor for calculating prefixed import library member suggestions
+ * `completion.getSuggestions` request results.
+ */
+class LibraryMemberContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ // Determine if the target looks like a library prefix
+ if (request.dotTarget is! SimpleIdentifier) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the expression and the containing library
+ await request.resolveExpression(request.dotTarget);
+
+ // Recompute the target since resolution may have changed it
+ Expression targetId = request.dotTarget;
+ if (targetId is SimpleIdentifier && !request.target.isCascade) {
+ Element elem = targetId.bestElement;
+ if (elem is PrefixElement) {
+ List<Directive> directives = await request.resolveDirectives();
+ LibraryElement containingLibrary = request.libraryElement;
+ // Gracefully degrade if the library or directives
+ // could not be determined (e.g. detached part file or source change)
+ if (containingLibrary != null && directives != null) {
+ return _buildSuggestions(
+ request, elem, containingLibrary, directives);
+ }
+ }
+ }
+ return EMPTY_LIST;
+ }
+
+ List<CompletionSuggestion> _buildSuggestions(
+ DartCompletionRequest request,
+ PrefixElement elem,
+ LibraryElement containingLibrary,
+ List<Directive> directives) {
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (Directive directive in directives) {
+ if (directive is ImportDirective) {
+ if (directive.prefix != null) {
+ if (directive.prefix.name == elem.name) {
+ LibraryElement library = directive.uriElement;
+
+ // Suggest elements from the imported library
+ if (library != null) {
+ AstNode parent = request.target.containingNode.parent;
+ bool isConstructor = parent.parent is ConstructorName;
+ bool typesOnly = parent is TypeName;
+ bool instCreation = typesOnly && isConstructor;
+ LibraryElementSuggestionBuilder builder =
+ new LibraryElementSuggestionBuilder(
+ containingLibrary,
+ CompletionSuggestionKind.INVOCATION,
+ typesOnly,
+ instCreation);
+ library.visitChildren(builder);
+ suggestions.addAll(builder.suggestions);
+
+ // If the import is 'deferred' then suggest 'loadLibrary'
+ if (directive.deferredKeyword != null) {
+ FunctionElement loadLibFunct = library.loadLibraryFunction;
+ suggestions.add(createSuggestion(loadLibFunct));
+ }
+ }
+ }
+ }
+ }
+ }
+ return suggestions;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
new file mode 100644
index 0000000..791c122
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/library_prefix_contributor.dart
@@ -0,0 +1,55 @@
+// 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.library_prefix;
+
+import 'dart:async';
+
+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';
+
+import '../../../protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
+
+/**
+ * A contributor for calculating prefixed import library member suggestions
+ * `completion.getSuggestions` request results.
+ */
+class LibraryPrefixContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ if (!request.includeIdentifiers) {
+ return EMPTY_LIST;
+ }
+
+ List<Directive> directives = await request.resolveDirectives();
+ if (directives == null) {
+ return EMPTY_LIST;
+ }
+
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (Directive directive in directives) {
+ if (directive is ImportDirective) {
+ SimpleIdentifier prefix = directive.prefix;
+ ImportElement element = directive.element;
+ if (prefix != null && element != null) {
+ String completion = prefix.name;
+ LibraryElement libElem = element.importedLibrary;
+ if (completion != null && completion.length > 0 && libElem != null) {
+ CompletionSuggestion suggestion = createSuggestion(libElem,
+ completion: completion,
+ kind: CompletionSuggestionKind.IDENTIFIER);
+ if (suggestion != null) {
+ suggestions.add(suggestion);
+ }
+ }
+ }
+ }
+ }
+ return suggestions;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
new file mode 100644
index 0000000..86640d9
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/named_constructor_contributor.dart
@@ -0,0 +1,83 @@
+// 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.contributor.dart.named_constructor;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart' hide Element;
+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:analysis_server/src/services/completion/dart/suggestion_builder.dart';
+
+/**
+ * A contributor for calculating named constructor suggestions
+ * such as suggesting `bar` in `new Foo.bar()`.
+ */
+class NamedConstructorContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ // Determine if the target looks like a named constructor.
+ AstNode parsedNode = request.target.containingNode;
+ SimpleIdentifier targetId;
+ if (parsedNode is ConstructorName) {
+ TypeName type = parsedNode.type;
+ if (type != null) {
+ targetId = type.name;
+ }
+ } else if (parsedNode is PrefixedIdentifier) {
+ // Some PrefixedIdentifier nodes are transformed into
+ // ConstructorName nodes during the resolution process.
+ targetId = parsedNode.prefix;
+ }
+ if (targetId == null) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the target to determine the type
+ await request.resolveExpression(targetId);
+
+ // Recompute the target since resolution may have changed it
+ AstNode node = request.target.containingNode;
+ LibraryElement libElem = request.libraryElement;
+ if (libElem == null) {
+ return EMPTY_LIST;
+ }
+
+ // Build the list of suggestions
+ if (node is ConstructorName) {
+ TypeName typeName = node.type;
+ if (typeName != null) {
+ DartType type = typeName.type;
+ if (type != null) {
+ Element classElem = type.element;
+ if (classElem is ClassElement) {
+ return _buildSuggestions(libElem, classElem);
+ }
+ }
+ }
+ }
+ return EMPTY_LIST;
+ }
+
+ List<CompletionSuggestion> _buildSuggestions(
+ LibraryElement libElem, ClassElement classElem) {
+ bool isLocalClassDecl = classElem.library == libElem;
+ List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ for (ConstructorElement elem in classElem.constructors) {
+ if (isLocalClassDecl || !elem.isPrivate) {
+ String name = elem.name;
+ if (name != null) {
+ CompletionSuggestion s = createSuggestion(elem, completion: name);
+ if (s != null) {
+ suggestions.add(s);
+ }
+ }
+ }
+ }
+ return suggestions;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
new file mode 100644
index 0000000..d1d2816
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/static_member_contributor.dart
@@ -0,0 +1,143 @@
+// 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.contributor.dart.static_member;
+
+import 'dart:async';
+
+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';
+
+import '../../../protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
+
+/**
+ * A contributor for calculating static member invocation / access suggestions
+ * `completion.getSuggestions` request results.
+ */
+class StaticMemberContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ // Determine if the target looks like a static method invocation,
+ // or a static property access
+ if (request.dotTarget is! Identifier || request.target.isCascade) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the expression and the containing library
+ await request.resolveExpression(request.dotTarget);
+
+ // Recompute the target since resolution may have changed it
+ Expression targetId = request.dotTarget;
+ if (targetId is Identifier && !request.target.isCascade) {
+ Element elem = targetId.bestElement;
+ if (elem is ClassElement) {
+ LibraryElement containingLibrary = request.libraryElement;
+ // Gracefully degrade if the library could not be determined
+ // e.g. detached part file or source change
+ if (containingLibrary == null) {
+ return EMPTY_LIST;
+ }
+
+ _SuggestionBuilder builder = new _SuggestionBuilder(containingLibrary);
+ elem.accept(builder);
+ return builder.suggestions;
+ }
+ }
+ return EMPTY_LIST;
+ }
+}
+
+/**
+ * This class visits elements in a class and provides suggestions based upon
+ * the visible static members in that class.
+ */
+class _SuggestionBuilder extends GeneralizingElementVisitor {
+ /**
+ * The library containing the unit in which the completion is requested.
+ */
+ final LibraryElement containingLibrary;
+
+ /**
+ * A collection of completion suggestions.
+ */
+ final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+
+ _SuggestionBuilder(this.containingLibrary);
+
+ @override
+ visitClassElement(ClassElement element) {
+ element.visitChildren(this);
+ }
+
+ @override
+ visitElement(Element element) {
+ // ignored
+ }
+
+ @override
+ visitFieldElement(FieldElement element) {
+ if (element.isStatic) {
+ _addSuggestion(element);
+ }
+ }
+
+ @override
+ visitMethodElement(MethodElement element) {
+ if (element.isStatic && !element.isOperator) {
+ _addSuggestion(element);
+ }
+ }
+
+ @override
+ visitPropertyAccessorElement(PropertyAccessorElement element) {
+ if (element.isStatic) {
+ _addSuggestion(element);
+ }
+ }
+
+ /**
+ * Add a suggestion based upon the given element.
+ */
+ void _addSuggestion(Element element) {
+ if (element.isPrivate) {
+ if (element.library != containingLibrary) {
+ // Do not suggest private members for imported libraries
+ return;
+ }
+ }
+ if (element.isSynthetic) {
+ if ((element is PropertyAccessorElement) ||
+ element is FieldElement && !_isSpecialEnumField(element)) {
+ return;
+ }
+ }
+ String completion = element.displayName;
+ if (completion == null || completion.length <= 0) {
+ return;
+ }
+ CompletionSuggestion suggestion =
+ createSuggestion(element, completion: completion);
+ 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;
+ }
+}
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
index fa0cf95..0e395fa 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/suggestion_builder.dart
@@ -112,9 +112,9 @@
CompletionSuggestionKind get kind;
/**
- * Return the request on which the builder is operating.
+ * Return the library in which the completion is requested.
*/
- DartCompletionRequest get request;
+ LibraryElement get containingLibrary;
/**
* Add a suggestion based upon the given element.
@@ -122,13 +122,7 @@
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) {
+ if (element.library != containingLibrary) {
return;
}
}
@@ -173,18 +167,17 @@
/**
* This class visits elements in a library and provides suggestions based upon
- * the visible members in that library. Clients should call
- * [LibraryElementSuggestionBuilder.suggestionsFor].
+ * the visible members in that library.
*/
class LibraryElementSuggestionBuilder extends GeneralizingElementVisitor
with ElementSuggestionBuilder {
- final DartCompletionRequest request;
+ final LibraryElement containingLibrary;
final CompletionSuggestionKind kind;
final bool typesOnly;
final bool instCreation;
LibraryElementSuggestionBuilder(
- this.request, this.kind, this.typesOnly, this.instCreation);
+ this.containingLibrary, this.kind, this.typesOnly, this.instCreation);
@override
visitClassElement(ClassElement element) {
@@ -244,19 +237,4 @@
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/dart/type_member_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
new file mode 100644
index 0000000..8915a65
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/completion/dart/type_member_contributor.dart
@@ -0,0 +1,412 @@
+// 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.type_member;
+
+import 'dart:async';
+import 'dart:collection';
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/suggestion_builder.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 '../../../protocol_server.dart'
+ show CompletionSuggestion, CompletionSuggestionKind;
+
+/**
+ * A contributor for calculating instance invocation / access suggestions
+ * `completion.getSuggestions` request results.
+ */
+class TypeMemberContributor extends DartCompletionContributor {
+ @override
+ Future<List<CompletionSuggestion>> computeSuggestions(
+ DartCompletionRequest request) async {
+ // Determine if the target looks like a prefixed identifier,
+ // a method invocation, or a property access
+ Expression parsedExpression = request.dotTarget;
+ if (parsedExpression == null) {
+ return EMPTY_LIST;
+ }
+
+ // Resolve the expression and the containing library
+ await request.resolveExpression(parsedExpression);
+ LibraryElement containingLibrary = request.libraryElement;
+ // Gracefully degrade if the library element could not be resolved
+ // e.g. detached part file or source change
+ if (containingLibrary == null) {
+ return EMPTY_LIST;
+ }
+
+ // Recompute the target since resolution may have changed it
+ Expression expression = request.dotTarget;
+ if (expression == null || expression.isSynthetic) {
+ return EMPTY_LIST;
+ }
+ if (expression is Identifier) {
+ Element elem = expression.bestElement;
+ if (elem is ClassElement) {
+ // Suggestions provided by StaticMemberContributor
+ return EMPTY_LIST;
+ }
+ if (elem is PrefixElement) {
+ // Suggestions provided by LibraryMemberContributor
+ return EMPTY_LIST;
+ }
+ }
+
+ // Determine the target expression's type
+ DartType type = expression.bestType;
+ if (type.isDynamic) {
+ // If the expression does not provide a good type
+ // then attempt to get a better type from the element
+ if (expression is Identifier) {
+ Element elem = expression.bestElement;
+ if (elem is FunctionTypedElement) {
+ type = elem.returnType;
+ } else if (elem is ParameterElement) {
+ type = elem.type;
+ } else if (elem is LocalVariableElement) {
+ type = elem.type;
+ }
+ if (type.isDynamic && expression is SimpleIdentifier) {
+ // If the element does not provide a good type
+ // then attempt to get a better type from a local declaration
+ _LocalBestTypeVisitor visitor =
+ new _LocalBestTypeVisitor(expression.name, request.offset);
+ if (visitor.visit(expression) && visitor.typeFound != null) {
+ type = visitor.typeFound;
+ }
+ }
+ }
+ }
+ String containingMethodName;
+ if (expression is SuperExpression && type is InterfaceType) {
+ // Suggest members from superclass if target is "super"
+ type = (type as InterfaceType).superclass;
+ // Determine the name of the containing method because
+ // the most likely completion is a super expression with same name
+ MethodDeclaration containingMethod =
+ expression.getAncestor((p) => p is MethodDeclaration);
+ if (containingMethod != null) {
+ SimpleIdentifier id = containingMethod.name;
+ if (id != null) {
+ containingMethodName = id.name;
+ }
+ }
+ }
+ if (type.isDynamic) {
+ // Suggest members from object if target is "dynamic"
+ type = request.objectType;
+ }
+
+ // Build the suggestions
+ if (type is InterfaceType) {
+ _SuggestionBuilder builder = new _SuggestionBuilder(containingLibrary);
+ builder.buildSuggestions(type, containingMethodName);
+ return builder.suggestions.toList();
+ }
+ return EMPTY_LIST;
+ }
+}
+
+/**
+ * An [AstVisitor] which looks for a declaration with the given name
+ * and if found, tries to determine a type for that declaration.
+ */
+class _LocalBestTypeVisitor extends LocalDeclarationVisitor {
+ /**
+ * The name for the declaration to be found.
+ */
+ final String targetName;
+
+ /**
+ * The best type for the found declaration,
+ * or `null` if no declaration found or failed to determine a type.
+ */
+ DartType typeFound;
+
+ /**
+ * Construct a new instance to search for a declaration
+ */
+ _LocalBestTypeVisitor(this.targetName, int offset) : super(offset);
+
+ @override
+ void declaredClass(ClassDeclaration declaration) {
+ if (declaration.name.name == targetName) {
+ // no type
+ finished();
+ }
+ }
+
+ @override
+ void declaredClassTypeAlias(ClassTypeAlias declaration) {
+ if (declaration.name.name == targetName) {
+ // no type
+ finished();
+ }
+ }
+
+ @override
+ void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
+ if (varDecl.name.name == targetName) {
+ // Type provided by the element in computeFull above
+ finished();
+ }
+ }
+
+ @override
+ void declaredFunction(FunctionDeclaration declaration) {
+ if (declaration.name.name == targetName) {
+ TypeName typeName = declaration.returnType;
+ if (typeName != null) {
+ typeFound = typeName.type;
+ }
+ finished();
+ }
+ }
+
+ @override
+ void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
+ if (declaration.name.name == targetName) {
+ TypeName typeName = declaration.returnType;
+ if (typeName != null) {
+ typeFound = typeName.type;
+ }
+ finished();
+ }
+ }
+
+ @override
+ void declaredLabel(Label label, bool isCaseLabel) {
+ if (label.label.name == targetName) {
+ // no type
+ finished();
+ }
+ }
+
+ @override
+ void declaredLocalVar(SimpleIdentifier name, TypeName type) {
+ if (name.name == targetName) {
+ typeFound = name.bestType;
+ finished();
+ }
+ }
+
+ @override
+ void declaredMethod(MethodDeclaration declaration) {
+ if (declaration.name.name == targetName) {
+ TypeName typeName = declaration.returnType;
+ if (typeName != null) {
+ typeFound = typeName.type;
+ }
+ finished();
+ }
+ }
+
+ @override
+ void declaredParam(SimpleIdentifier name, TypeName type) {
+ if (name.name == targetName) {
+ // Type provided by the element in computeFull above
+ finished();
+ }
+ }
+
+ @override
+ void declaredTopLevelVar(
+ VariableDeclarationList varList, VariableDeclaration varDecl) {
+ if (varDecl.name.name == targetName) {
+ // Type provided by the element in computeFull above
+ finished();
+ }
+ }
+}
+
+/**
+ * This class provides suggestions based upon the visible instance members in
+ * an interface type.
+ */
+class _SuggestionBuilder {
+ /**
+ * Enumerated value indicating that we have not generated any completions for
+ * a given identifier yet.
+ */
+ static const int _COMPLETION_TYPE_NONE = 0;
+
+ /**
+ * Enumerated value indicating that we have generated a completion for a
+ * getter.
+ */
+ static const int _COMPLETION_TYPE_GETTER = 1;
+
+ /**
+ * Enumerated value indicating that we have generated a completion for a
+ * setter.
+ */
+ static const int _COMPLETION_TYPE_SETTER = 2;
+
+ /**
+ * Enumerated value indicating that we have generated a completion for a
+ * field, a method, or a getter/setter pair.
+ */
+ static const int _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET = 3;
+
+ /**
+ * The library containing the unit in which the completion is requested.
+ */
+ final LibraryElement containingLibrary;
+
+ /**
+ * Map indicating, for each possible completion identifier, whether we have
+ * already generated completions for a getter, setter, or both. The "both"
+ * case also handles the case where have generated a completion for a method
+ * or a field.
+ *
+ * Note: the enumerated values stored in this map are intended to be bitwise
+ * compared.
+ */
+ Map<String, int> _completionTypesGenerated = new HashMap<String, int>();
+
+ /**
+ * Map from completion identifier to completion suggestion
+ */
+ Map<String, CompletionSuggestion> _suggestionMap =
+ <String, CompletionSuggestion>{};
+
+ _SuggestionBuilder(this.containingLibrary);
+
+ Iterable<CompletionSuggestion> get suggestions => _suggestionMap.values;
+
+ /**
+ * Add a suggestion based upon the given element, provided that it is not
+ * shadowed by a previously added suggestion.
+ */
+ void _addSuggestion(Element element,
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
+ if (element.isPrivate) {
+ if (element.library != containingLibrary) {
+ // Do not suggest private members for imported libraries
+ return;
+ }
+ }
+ String identifier = element.displayName;
+ int alreadyGenerated = _completionTypesGenerated.putIfAbsent(
+ identifier, () => _COMPLETION_TYPE_NONE);
+ if (element is MethodElement) {
+ // Anything shadows a method.
+ if (alreadyGenerated != _COMPLETION_TYPE_NONE) {
+ return;
+ }
+ _completionTypesGenerated[identifier] =
+ _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET;
+ } else if (element is PropertyAccessorElement) {
+ if (element.isGetter) {
+ // Getters, fields, and methods shadow a getter.
+ if ((alreadyGenerated & _COMPLETION_TYPE_GETTER) != 0) {
+ return;
+ }
+ _completionTypesGenerated[identifier] |= _COMPLETION_TYPE_GETTER;
+ } else {
+ // Setters, fields, and methods shadow a setter.
+ if ((alreadyGenerated & _COMPLETION_TYPE_SETTER) != 0) {
+ return;
+ }
+ _completionTypesGenerated[identifier] |= _COMPLETION_TYPE_SETTER;
+ }
+ } else if (element is FieldElement) {
+ // Fields and methods shadow a field. A getter/setter pair shadows a
+ // field, but a getter or setter by itself doesn't.
+ if (alreadyGenerated == _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET) {
+ return;
+ }
+ _completionTypesGenerated[identifier] =
+ _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET;
+ } else {
+ // Unexpected element type; skip it.
+ assert(false);
+ return;
+ }
+ CompletionSuggestion suggestion =
+ createSuggestion(element, relevance: relevance);
+ if (suggestion != null) {
+ _suggestionMap[suggestion.completion] = suggestion;
+ }
+ }
+
+ /**
+ * Return completion suggestions for 'dot' completions on the given [type].
+ * If the 'dot' completion is a super expression, then [containingMethodName]
+ * is the name of the method in which the completion is requested.
+ */
+ void buildSuggestions(InterfaceType type, String containingMethodName) {
+ // Visit all of the types in the class hierarchy, collecting possible
+ // completions. If multiple elements are found that complete to the same
+ // identifier, addSuggestion will discard all but the first (with a few
+ // exceptions to handle getter/setter pairs).
+ List<InterfaceType> types = _getTypeOrdering(type);
+ for (InterfaceType targetType in types) {
+ for (MethodElement method in targetType.methods) {
+ // Exclude static methods when completion on an instance
+ if (!method.isStatic) {
+ // Boost the relevance of a super expression
+ // calling a method of the same name as the containing method
+ _addSuggestion(method,
+ relevance: method.name == containingMethodName
+ ? DART_RELEVANCE_HIGH
+ : DART_RELEVANCE_DEFAULT);
+ }
+ }
+ for (PropertyAccessorElement propertyAccessor in targetType.accessors) {
+ if (!propertyAccessor.isStatic) {
+ if (propertyAccessor.isSynthetic) {
+ // Avoid visiting a field twice
+ if (propertyAccessor.isGetter) {
+ _addSuggestion(propertyAccessor.variable);
+ }
+ } else {
+ _addSuggestion(propertyAccessor);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Get a list of [InterfaceType]s that should be searched to find the
+ * possible completions for an object having type [type].
+ */
+ List<InterfaceType> _getTypeOrdering(InterfaceType type) {
+ // Candidate completions can come from [type] as well as any types above it
+ // in the class hierarchy (including mixins, superclasses, and interfaces).
+ // If a given completion identifier shows up in multiple types, we should
+ // use the element that is nearest in the superclass chain, so we will
+ // visit [type] first, then its mixins, then its superclass, then its
+ // superclass's mixins, etc., and only afterwards visit interfaces.
+ //
+ // We short-circuit loops in the class hierarchy by keeping track of the
+ // classes seen (not the interfaces) so that we won't be fooled by nonsense
+ // like "class C<T> extends C<List<T>> {}"
+ List<InterfaceType> result = <InterfaceType>[];
+ Set<ClassElement> classesSeen = new HashSet<ClassElement>();
+ List<InterfaceType> typesToVisit = <InterfaceType>[type];
+ while (typesToVisit.isNotEmpty) {
+ InterfaceType nextType = typesToVisit.removeLast();
+ if (!classesSeen.add(nextType.element)) {
+ // Class had already been seen, so ignore this type.
+ continue;
+ }
+ result.add(nextType);
+ // typesToVisit is a stack, so push on the interfaces first, then the
+ // superclass, then the mixins. This will ensure that they are visited
+ // in the reverse order.
+ typesToVisit.addAll(nextType.interfaces);
+ if (nextType.superclass != null) {
+ typesToVisit.add(nextType.superclass);
+ }
+ typesToVisit.addAll(nextType.mixins);
+ }
+ return result;
+ }
+}
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
index ebf87fe..7e849b1 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/uri_contributor.dart
@@ -116,10 +116,19 @@
if (resContext.isRelative(dirPath)) {
String sourceDirPath = resContext.dirname(source.fullName);
if (resContext.isAbsolute(sourceDirPath)) {
- dirPath = resContext.join(sourceDirPath, dirPath);
+ dirPath = resContext.normalize(resContext.join(sourceDirPath, dirPath));
} else {
return;
}
+ // Do not suggest relative paths reaching outside the 'lib' directory.
+ bool srcInLib = resContext.split(sourceDirPath).contains('lib');
+ bool dstInLib = resContext.split(dirPath).contains('lib');
+ if (srcInLib && !dstInLib) {
+ return;
+ }
+ }
+ if (dirPath.endsWith('\\.')) {
+ dirPath = dirPath.substring(0, dirPath.length - 1);
}
Resource dir = resProvider.getResource(dirPath);
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
index 2fbe91e..be84372 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_cache.dart
@@ -31,12 +31,6 @@
String _importKey;
/**
- * Library prefix suggestions based upon imports,
- * or `null` if nothing has been cached.
- */
- List<CompletionSuggestion> libraryPrefixSuggestions;
-
- /**
* Type suggestions based upon imports,
* or `null` if nothing has been cached.
*/
@@ -114,7 +108,6 @@
Future<bool> computeImportInfo(CompilationUnit unit,
SearchEngine searchEngine, bool shouldWaitForLowPrioritySuggestions) {
importedTypeSuggestions = <CompletionSuggestion>[];
- libraryPrefixSuggestions = <CompletionSuggestion>[];
otherImportedSuggestions = <CompletionSuggestion>[];
importedConstructorSuggestions = <CompletionSuggestion>[];
importedVoidReturnSuggestions = <CompletionSuggestion>[];
@@ -240,8 +233,9 @@
} else {
// Exclude elements from prefixed imports
// because they are provided by PrefixedElementContributor
- _addLibraryPrefixSuggestion(importElem);
- excludedLibs.add(importElem.importedLibrary);
+ // Suggested by LibraryPrefixContributor
+ // _addLibraryPrefixSuggestion(importElem);
+ // excludedLibs.add(importElem.importedLibrary);
}
}
} else if (directive is PartDirective) {
@@ -257,27 +251,6 @@
}
}
- void _addLibraryPrefixSuggestion(ImportElement importElem) {
- CompletionSuggestion suggestion = null;
- String completion = importElem.prefix.displayName;
- if (completion != null && completion.length > 0) {
- suggestion = new CompletionSuggestion(
- CompletionSuggestionKind.INVOCATION,
- DART_RELEVANCE_DEFAULT,
- completion,
- completion.length,
- 0,
- importElem.isDeprecated,
- false);
- LibraryElement lib = importElem.importedLibrary;
- if (lib != null) {
- suggestion.element = convertElement(lib);
- }
- libraryPrefixSuggestions.add(suggestion);
- _importedCompletions.add(suggestion.completion);
- }
- }
-
/**
* Add suggestions for all top level elements in the context
* excluding those elemnents for which suggestions have already been added.
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 06bbe66..4f793ec 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
@@ -18,11 +18,10 @@
import 'package:analysis_server/src/services/completion/imported_reference_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/search/search_engine.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/engine.dart' hide AnalysisContextImpl;
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/scanner.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -99,7 +98,7 @@
//new KeywordContributor(),
//new ArgListContributor(),
// new CombinatorContributor(),
- new PrefixedElementContributor(),
+ // new PrefixedElementContributor(),
//new UriContributor(),
// TODO(brianwilkerson) Use the completion contributor extension point
// to add the contributor below (and eventually, all the contributors).
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
index b283ce9..f2a9cfa 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_reference_contributor.dart
@@ -143,7 +143,6 @@
}
DartCompletionCache cache = request.cache;
_addFilteredSuggestions(filterText, cache.importedConstructorSuggestions);
- _addFilteredSuggestions(filterText, cache.libraryPrefixSuggestions);
}
/**
@@ -258,7 +257,6 @@
DartCompletionCache cache = request.cache;
if (optype.includeTypeNameSuggestions) {
_addFilteredSuggestions(filterText, cache.importedTypeSuggestions);
- _addFilteredSuggestions(filterText, cache.libraryPrefixSuggestions);
}
if (optype.includeReturnValueSuggestions) {
_addFilteredSuggestions(filterText, cache.otherImportedSuggestions);
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index 3408e96..768b0d3 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -129,6 +129,14 @@
}
}
+@override
+ void visitAssertStatement(AssertStatement node) {
+ if (identical(entity, node.condition)) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+ }
+
void visitAssignmentExpression(AssignmentExpression node) {
if (identical(entity, node.rightHandSide)) {
optype.includeReturnValueSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart b/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
deleted file mode 100644
index b6fe585..0000000
--- a/pkg/analysis_server/lib/src/services/completion/prefixed_element_contributor.dart
+++ /dev/null
@@ -1,370 +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.invocation;
-
-import 'dart:async';
-
-import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
-import 'package:analysis_server/src/services/completion/local_declaration_visitor.dart';
-import 'package:analysis_server/src/services/completion/local_suggestion_builder.dart'
- hide createSuggestion;
-import 'package:analysis_server/src/services/completion/optype.dart';
-import 'package:analysis_server/src/services/completion/suggestion_builder.dart';
-import 'package:analysis_server/src/services/completion/suggestion_builder.dart'
- show createSuggestion;
-import 'package:analyzer/src/generated/ast.dart';
-import 'package:analyzer/src/generated/element.dart';
-
-import '../../protocol_server.dart'
- show CompletionSuggestion, CompletionSuggestionKind;
-
-/**
- * A contributor for calculating invocation / access suggestions
- * `completion.getSuggestions` request results.
- */
-class PrefixedElementContributor extends DartCompletionContributor {
- SuggestionBuilder builder;
-
- @override
- bool computeFast(DartCompletionRequest request) {
- OpType optype = request.optype;
- if (optype.isPrefixed) {
- builder = request.target.containingNode
- .accept(new _InvocationAstVisitor(request));
- if (builder != null) {
- return builder.computeFast(request.target.containingNode);
- }
- }
-
- return true;
- }
-
- @override
- Future<bool> computeFull(DartCompletionRequest request) {
- if (builder != null) {
- return builder.computeFull(request.target.containingNode);
- }
- return new Future.value(false);
- }
-}
-
-class _ExpressionSuggestionBuilder implements SuggestionBuilder {
- final DartCompletionRequest request;
-
- _ExpressionSuggestionBuilder(this.request);
-
- @override
- bool computeFast(AstNode node) {
- return false;
- }
-
- @override
- Future<bool> computeFull(AstNode node) {
- if (node is MethodInvocation) {
- node = (node as MethodInvocation).realTarget;
- } else if (node is PropertyAccess) {
- node = (node as PropertyAccess).realTarget;
- }
- if (node is Identifier) {
- Element elem = node.bestElement;
- if (elem is ClassElement || elem is PrefixElement) {
- elem.accept(new _PrefixedIdentifierSuggestionBuilder(request));
- return new Future.value(true);
- }
- }
- if (node is Expression) {
- String containingMethodName;
- bool isSuper = node is SuperExpression;
- if (isSuper) {
- MethodDeclaration containingMethod =
- node.getAncestor((p) => p is MethodDeclaration);
- if (containingMethod != null) {
- SimpleIdentifier id = containingMethod.name;
- if (id != null) {
- containingMethodName = id.name;
- }
- }
- }
- InterfaceTypeSuggestionBuilder.suggestionsFor(request, node.bestType,
- isSuper: isSuper, containingMethodName: containingMethodName);
- return new Future.value(true);
- }
- return new Future.value(false);
- }
-}
-
-/**
- * An [AstNode] vistor for determining which suggestion builder
- * should be used to build invocation/access suggestions.
- */
-class _InvocationAstVisitor extends GeneralizingAstVisitor<SuggestionBuilder> {
- final DartCompletionRequest request;
-
- _InvocationAstVisitor(this.request);
-
- @override
- SuggestionBuilder visitConstructorName(ConstructorName node) {
- // some PrefixedIdentifier nodes are transformed into
- // ConstructorName nodes during the resolution process.
- return new _PrefixedIdentifierSuggestionBuilder(request);
- }
-
- @override
- SuggestionBuilder visitMethodInvocation(MethodInvocation node) {
- return new _ExpressionSuggestionBuilder(request);
- }
-
- @override
- SuggestionBuilder visitNode(AstNode node) {
- return null;
- }
-
- @override
- SuggestionBuilder visitPrefixedIdentifier(PrefixedIdentifier node) {
- // some PrefixedIdentifier nodes are transformed into
- // ConstructorName nodes during the resolution process.
- return new _PrefixedIdentifierSuggestionBuilder(request);
- }
-
- @override
- SuggestionBuilder visitPropertyAccess(PropertyAccess node) {
- return new _ExpressionSuggestionBuilder(request);
- }
-}
-
-/**
- * An [AstVisitor] which looks for a declaration with the given name
- * and if found, tries to determine a type for that declaration.
- */
-class _LocalBestTypeVisitor extends LocalDeclarationVisitor {
- /**
- * The name for the declaration to be found.
- */
- final String targetName;
-
- /**
- * The best type for the found declaration,
- * or `null` if no declaration found or failed to determine a type.
- */
- DartType typeFound;
-
- /**
- * Construct a new instance to search for a declaration
- */
- _LocalBestTypeVisitor(this.targetName, int offset) : super(offset);
-
- @override
- void declaredClass(ClassDeclaration declaration) {
- if (declaration.name.name == targetName) {
- // no type
- finished();
- }
- }
-
- @override
- void declaredClassTypeAlias(ClassTypeAlias declaration) {
- if (declaration.name.name == targetName) {
- // no type
- finished();
- }
- }
-
- @override
- void declaredField(FieldDeclaration fieldDecl, VariableDeclaration varDecl) {
- if (varDecl.name.name == targetName) {
- // Type provided by the element in computeFull above
- finished();
- }
- }
-
- @override
- void declaredFunction(FunctionDeclaration declaration) {
- if (declaration.name.name == targetName) {
- TypeName typeName = declaration.returnType;
- if (typeName != null) {
- typeFound = typeName.type;
- }
- finished();
- }
- }
-
- @override
- void declaredFunctionTypeAlias(FunctionTypeAlias declaration) {
- if (declaration.name.name == targetName) {
- TypeName typeName = declaration.returnType;
- if (typeName != null) {
- typeFound = typeName.type;
- }
- finished();
- }
- }
-
- @override
- void declaredLabel(Label label, bool isCaseLabel) {
- if (label.label.name == targetName) {
- // no type
- finished();
- }
- }
-
- @override
- void declaredLocalVar(SimpleIdentifier name, TypeName type) {
- if (name.name == targetName) {
- typeFound = name.bestType;
- finished();
- }
- }
-
- @override
- void declaredMethod(MethodDeclaration declaration) {
- if (declaration.name.name == targetName) {
- TypeName typeName = declaration.returnType;
- if (typeName != null) {
- typeFound = typeName.type;
- }
- finished();
- }
- }
-
- @override
- void declaredParam(SimpleIdentifier name, TypeName type) {
- if (name.name == targetName) {
- // Type provided by the element in computeFull above
- finished();
- }
- }
-
- @override
- void declaredTopLevelVar(
- VariableDeclarationList varList, VariableDeclaration varDecl) {
- if (varDecl.name.name == targetName) {
- // Type provided by the element in computeFull above
- finished();
- }
- }
-}
-
-/**
- * An [Element] visitor for determining the appropriate invocation/access
- * suggestions based upon the element for which the completion is requested.
- */
-class _PrefixedIdentifierSuggestionBuilder
- extends GeneralizingElementVisitor<Future<bool>>
- implements SuggestionBuilder {
- final DartCompletionRequest request;
-
- _PrefixedIdentifierSuggestionBuilder(this.request);
-
- @override
- bool computeFast(AstNode node) {
- return false;
- }
-
- @override
- Future<bool> computeFull(AstNode node) {
- if (node is ConstructorName) {
- // some PrefixedIdentifier nodes are transformed into
- // ConstructorName nodes during the resolution process.
- return new NamedConstructorSuggestionBuilder(request).computeFull(node);
- }
- if (node is PrefixedIdentifier) {
- SimpleIdentifier prefix = node.prefix;
- if (prefix != null) {
- Element element = prefix.bestElement;
- DartType type = prefix.bestType;
- if (element is! ClassElement) {
- if (type == null || type.isDynamic) {
- //
- // Given `g. int y = 0;`, the parser interprets `g` as a prefixed
- // identifier with no type.
- // If the user is requesting completions for `g`,
- // then check for a function, getter, or similar with a type.
- //
- _LocalBestTypeVisitor visitor =
- new _LocalBestTypeVisitor(prefix.name, request.offset);
- if (visitor.visit(prefix)) {
- type = visitor.typeFound;
- }
- }
- if (type != null && !type.isDynamic) {
- InterfaceTypeSuggestionBuilder.suggestionsFor(request, type);
- return new Future.value(true);
- }
- }
- if (element != null) {
- return element.accept(this);
- }
- }
- }
- return new Future.value(false);
- }
-
- @override
- Future<bool> visitClassElement(ClassElement element) {
- if (element != null) {
- InterfaceType type = element.type;
- if (type != null) {
- StaticClassElementSuggestionBuilder.suggestionsFor(
- request, type.element);
- }
- }
- return new Future.value(false);
- }
-
- @override
- Future<bool> visitElement(Element element) {
- return new Future.value(false);
- }
-
- @override
- Future<bool> visitPrefixElement(PrefixElement element) {
- bool modified = false;
- // Find the import directive with the given prefix
- for (Directive directive in request.unit.directives) {
- if (directive is ImportDirective) {
- if (directive.prefix != null) {
- if (directive.prefix.name == element.name) {
- // Suggest elements from the imported library
- LibraryElement library = directive.uriElement;
- AstNode node = request.target.containingNode;
- bool typesOnly = node.parent is TypeName;
- bool instCreation =
- typesOnly && node.parent.parent is ConstructorName;
- LibraryElementSuggestionBuilder.suggestionsFor(
- request,
- CompletionSuggestionKind.INVOCATION,
- library,
- typesOnly,
- instCreation);
- modified = true;
- if (directive.deferredKeyword != null) {
- FunctionElement loadLibFunct = library.loadLibraryFunction;
- request.addSuggestion(createSuggestion(loadLibFunct));
- }
- }
- }
- }
- }
- return new Future.value(modified);
- }
-
- @override
- Future<bool> visitPropertyAccessorElement(PropertyAccessorElement element) {
- if (element != null) {
- PropertyInducingElement elemVar = element.variable;
- if (elemVar != null) {
- InterfaceTypeSuggestionBuilder.suggestionsFor(request, elemVar.type);
- }
- return new Future.value(true);
- }
- return new Future.value(false);
- }
-
- @override
- Future<bool> visitVariableElement(VariableElement element) {
- InterfaceTypeSuggestionBuilder.suggestionsFor(request, element.type);
- return new Future.value(true);
- }
-}
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 573dc4b..4379e7f 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -5,7 +5,6 @@
library services.completion.suggestion.builder;
import 'dart:async';
-import 'dart:collection';
import 'package:analysis_server/src/protocol_server.dart'
hide Element, ElementKind;
@@ -14,7 +13,6 @@
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;
export 'package:analysis_server/src/services/completion/dart/suggestion_builder.dart'
show createSuggestion;
@@ -174,421 +172,6 @@
}
/**
- * This class provides suggestions based upon the visible instance members in
- * an interface type. Clients should call
- * [InterfaceTypeSuggestionBuilder.suggestionsFor].
- */
-class InterfaceTypeSuggestionBuilder {
- /**
- * Enumerated value indicating that we have not generated any completions for
- * a given identifier yet.
- */
- static const int _COMPLETION_TYPE_NONE = 0;
-
- /**
- * Enumerated value indicating that we have generated a completion for a
- * getter.
- */
- static const int _COMPLETION_TYPE_GETTER = 1;
-
- /**
- * Enumerated value indicating that we have generated a completion for a
- * setter.
- */
- static const int _COMPLETION_TYPE_SETTER = 2;
-
- /**
- * Enumerated value indicating that we have generated a completion for a
- * field, a method, or a getter/setter pair.
- */
- static const int _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET = 3;
-
- final DartCompletionRequest request;
-
- /**
- * Map indicating, for each possible completion identifier, whether we have
- * already generated completions for a getter, setter, or both. The "both"
- * case also handles the case where have generated a completion for a method
- * or a field.
- *
- * Note: the enumerated values stored in this map are intended to be bitwise
- * compared.
- */
- Map<String, int> _completionTypesGenerated = new HashMap<String, int>();
-
- InterfaceTypeSuggestionBuilder(this.request);
-
- CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION;
-
- /**
- * Add a suggestion based upon the given element, provided that it is not
- * shadowed by a previously added suggestion.
- */
- void addSuggestion(Element element, {int relevance: DART_RELEVANCE_DEFAULT}) {
- if (element.isPrivate) {
- LibraryElement elementLibrary = element.library;
- LibraryElement unitLibrary = request.unit.element.library;
- if (elementLibrary != unitLibrary) {
- return;
- }
- }
- String identifier = element.displayName;
- int alreadyGenerated = _completionTypesGenerated.putIfAbsent(
- identifier, () => _COMPLETION_TYPE_NONE);
- if (element is MethodElement) {
- // Anything shadows a method.
- if (alreadyGenerated != _COMPLETION_TYPE_NONE) {
- return;
- }
- _completionTypesGenerated[identifier] =
- _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET;
- } else if (element is PropertyAccessorElement) {
- if (element.isGetter) {
- // Getters, fields, and methods shadow a getter.
- if ((alreadyGenerated & _COMPLETION_TYPE_GETTER) != 0) {
- return;
- }
- _completionTypesGenerated[identifier] |= _COMPLETION_TYPE_GETTER;
- } else {
- // Setters, fields, and methods shadow a setter.
- if ((alreadyGenerated & _COMPLETION_TYPE_SETTER) != 0) {
- return;
- }
- _completionTypesGenerated[identifier] |= _COMPLETION_TYPE_SETTER;
- }
- } else if (element is FieldElement) {
- // Fields and methods shadow a field. A getter/setter pair shadows a
- // field, but a getter or setter by itself doesn't.
- if (alreadyGenerated == _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET) {
- return;
- }
- _completionTypesGenerated[identifier] =
- _COMPLETION_TYPE_FIELD_OR_METHOD_OR_GETSET;
- } else {
- // Unexpected element type; skip it.
- assert(false);
- return;
- }
- CompletionSuggestion suggestion =
- createSuggestion(element, kind: kind, relevance: relevance);
- if (suggestion != null) {
- request.addSuggestion(suggestion);
- }
- }
-
- void _buildSuggestions(InterfaceType type, LibraryElement library,
- bool isSuper, String containingMethodName) {
- if (isSuper) {
- // Suggest members from superclass if the target is "super"
- type = type.superclass;
- if (type == null) {
- return;
- }
- }
- // Visit all of the types in the class hierarchy, collecting possible
- // completions. If multiple elements are found that complete to the same
- // identifier, addSuggestion will discard all but the first (with a few
- // exceptions to handle getter/setter pairs).
- List<InterfaceType> types = _getTypeOrdering(type);
- for (InterfaceType targetType in types) {
- for (MethodElement method in targetType.methods) {
- // Exclude static methods when completion on an instance
- if (!method.isStatic) {
- addSuggestion(method,
- relevance: method.name == containingMethodName
- ? DART_RELEVANCE_HIGH
- : DART_RELEVANCE_DEFAULT);
- }
- }
- for (PropertyAccessorElement propertyAccessor in targetType.accessors) {
- if (!propertyAccessor.isStatic) {
- if (propertyAccessor.isSynthetic) {
- // Avoid visiting a field twice
- if (propertyAccessor.isGetter) {
- addSuggestion(propertyAccessor.variable);
- }
- } else {
- addSuggestion(propertyAccessor);
- }
- }
- }
- }
- }
-
- /**
- * Get a list of [InterfaceType]s that should be searched to find the
- * possible completions for an object having type [type].
- */
- List<InterfaceType> _getTypeOrdering(InterfaceType type) {
- // Candidate completions can come from [type] as well as any types above it
- // in the class hierarchy (including mixins, superclasses, and interfaces).
- // If a given completion identifier shows up in multiple types, we should
- // use the element that is nearest in the superclass chain, so we will
- // visit [type] first, then its mixins, then its superclass, then its
- // superclass's mixins, etc., and only afterwards visit interfaces.
- //
- // We short-circuit loops in the class hierarchy by keeping track of the
- // classes seen (not the interfaces) so that we won't be fooled by nonsense
- // like "class C<T> extends C<List<T>> {}"
- List<InterfaceType> result = <InterfaceType>[];
- Set<ClassElement> classesSeen = new HashSet<ClassElement>();
- List<InterfaceType> typesToVisit = <InterfaceType>[type];
- while (typesToVisit.isNotEmpty) {
- InterfaceType nextType = typesToVisit.removeLast();
- if (!classesSeen.add(nextType.element)) {
- // Class had already been seen, so ignore this type.
- continue;
- }
- result.add(nextType);
- // typesToVisit is a stack, so push on the interfaces first, then the
- // superclass, then the mixins. This will ensure that they are visited
- // in the reverse order.
- typesToVisit.addAll(nextType.interfaces);
- if (nextType.superclass != null) {
- typesToVisit.add(nextType.superclass);
- }
- typesToVisit.addAll(nextType.mixins);
- }
- return result;
- }
-
- /**
- * Add suggestions for the visible members in the given interface
- */
- static void suggestionsFor(DartCompletionRequest request, DartType type,
- {bool isSuper: false, String containingMethodName: null}) {
- CompilationUnit compilationUnit =
- request.target.containingNode.getAncestor((n) => n is CompilationUnit);
- CompilationUnitElement unitElem = compilationUnit.element;
- if (unitElem == null) {
- engine.AnalysisEngine.instance.logger
- .logInformation('Completion expected resolved AST');
- return;
- }
- LibraryElement library = unitElem.library;
- if (type is DynamicTypeImpl) {
- type = request.cache.objectClassElement.type;
- }
- if (type is InterfaceType) {
- new InterfaceTypeSuggestionBuilder(request)
- ._buildSuggestions(type, library, isSuper, containingMethodName);
- }
- }
-}
-
-/**
- * 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));
- }
- }
-}
-
-/**
- * This class visits elements in a class and provides suggestions based upon
- * the visible named constructors in that class.
- */
-class NamedConstructorSuggestionBuilder extends GeneralizingElementVisitor
- with ElementSuggestionBuilder
- implements SuggestionBuilder {
- final DartCompletionRequest request;
-
- NamedConstructorSuggestionBuilder(this.request);
-
- @override
- CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION;
-
- @override
- bool computeFast(AstNode node) {
- return false;
- }
-
- @override
- Future<bool> computeFull(AstNode node) {
- if (node is SimpleIdentifier) {
- node = node.parent;
- }
- if (node is ConstructorName) {
- TypeName typeName = node.type;
- if (typeName != null) {
- DartType type = typeName.type;
- if (type != null) {
- if (type.element is ClassElement) {
- type.element.accept(this);
- }
- return new Future.value(true);
- }
- }
- }
- return new Future.value(false);
- }
-
- @override
- visitClassElement(ClassElement element) {
- element.visitChildren(this);
- }
-
- @override
- visitConstructorElement(ConstructorElement element) {
- addSuggestion(element);
- }
-
- @override
- visitElement(Element element) {
- // ignored
- }
-}
-
-/**
- * This class visits elements in a class and provides suggestions based upon
- * the visible static members in that class. Clients should call
- * [StaticClassElementSuggestionBuilder.suggestionsFor].
- */
-class StaticClassElementSuggestionBuilder extends GeneralizingElementVisitor
- with ElementSuggestionBuilder {
- final DartCompletionRequest request;
-
- StaticClassElementSuggestionBuilder(this.request);
-
- @override
- CompletionSuggestionKind get kind => CompletionSuggestionKind.INVOCATION;
-
- @override
- visitClassElement(ClassElement element) {
- element.visitChildren(this);
- element.allSupertypes.forEach((InterfaceType type) {
- type.element.visitChildren(this);
- });
- }
-
- @override
- visitElement(Element element) {
- // ignored
- }
-
- @override
- visitFieldElement(FieldElement element) {
- if (!element.isStatic) {
- return;
- }
- addSuggestion(element);
- }
-
- @override
- visitMethodElement(MethodElement element) {
- if (!element.isStatic) {
- return;
- }
- if (element.isOperator) {
- return;
- }
- addSuggestion(element);
- }
-
- @override
- visitPropertyAccessorElement(PropertyAccessorElement element) {
- if (!element.isStatic) {
- return;
- }
- addSuggestion(element);
- }
-
- /**
- * Add suggestions for the visible members in the given class
- */
- static void suggestionsFor(DartCompletionRequest request, Element element) {
- if (element == DynamicElementImpl.instance) {
- element = request.cache.objectClassElement;
- }
- if (element is ClassElement) {
- return element.accept(new StaticClassElementSuggestionBuilder(request));
- }
- }
-}
-
-/**
* Common interface implemented by suggestion builders.
*/
abstract class SuggestionBuilder {
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 c6f1c02..00c48a3 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -413,8 +413,8 @@
if (token is DocumentationCommentToken &&
token.type == TokenType.SINGLE_LINE_COMMENT) {
sb.append(prefix);
- sb.append(' * ');
- sb.append(token.lexeme.substring('/// '.length));
+ sb.append(' *');
+ sb.append(token.lexeme.substring('///'.length));
sb.append(eol);
} else {
return;
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 f068b3b..18465d0 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -453,11 +453,7 @@
PartDirective directive = node.parent;
Source partSource = directive.source;
CompilationUnit partUnit;
- if (AnalysisEngine.instance.useTaskModel) {
- partUnit = context.getResolvedCompilationUnit2(partSource, partSource);
- } else {
- partUnit = context.getResolvedCompilationUnit2(partSource, unitSource);
- }
+ partUnit = context.getResolvedCompilationUnit2(partSource, partSource);
if (partUnit != null) {
CorrectionUtils partUtils = new CorrectionUtils(partUnit);
CorrectionUtils_InsertDesc desc = partUtils.getInsertDescTop();
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 ad42a6e..f238cd5 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_local.dart
@@ -59,6 +59,7 @@
unitElement = unit.element;
selectionRange = new SourceRange(selectionOffset, selectionLength);
utils = new CorrectionUtils(unit);
+ file = unitElement.source.fullName;
}
@override
@@ -117,6 +118,7 @@
} else {
occurrences = [selectionRange];
}
+ occurrences.sort((a, b) => a.offset - b.offset);
// If the whole expression of a statement is selected, like '1 + 2',
// then convert it into a variable declaration statement.
if (wholeStatementExpression && occurrences.length == 1) {
@@ -127,36 +129,53 @@
doSourceChange_addElementEdit(change, unitElement, edit);
return new Future.value(change);
}
+ // prepare positions
+ List<Position> positions = <Position>[];
+ int occurrencesShift = 0;
+ void addPosition(int offset) {
+ positions.add(new Position(file, offset));
+ }
// add variable declaration
{
- String declarationSource;
+ String declarationCode;
+ int nameOffsetInDeclarationCode;
if (stringLiteralPart != null) {
- declarationSource = "var $name = '$stringLiteralPart';";
+ declarationCode = 'var ';
+ nameOffsetInDeclarationCode = declarationCode.length;
+ declarationCode += "$name = '$stringLiteralPart';";
} else {
String keyword = _declarationKeyword;
- String initializerSource = utils.getRangeText(selectionRange);
- declarationSource = "$keyword $name = $initializerSource;";
+ String initializerCode = utils.getRangeText(selectionRange);
+ declarationCode = '$keyword ';
+ nameOffsetInDeclarationCode = declarationCode.length;
+ declarationCode += '$name = $initializerCode;';
}
- String eol = utils.endOfLine;
// prepare location for declaration
AstNode target = _findDeclarationTarget(occurrences);
+ String eol = utils.endOfLine;
// insert variable declaration
if (target is Statement) {
String prefix = utils.getNodePrefix(target);
SourceEdit edit =
- new SourceEdit(target.offset, 0, declarationSource + eol + prefix);
+ new SourceEdit(target.offset, 0, declarationCode + eol + prefix);
doSourceChange_addElementEdit(change, unitElement, edit);
+ addPosition(edit.offset + nameOffsetInDeclarationCode);
+ occurrencesShift = edit.replacement.length;
} else if (target is ExpressionFunctionBody) {
String prefix = utils.getNodePrefix(target.parent);
String indent = utils.getIndent(1);
- String declStatement = prefix + indent + declarationSource + eol;
- String exprStatement = prefix + indent + 'return ';
Expression expr = target.expression;
- doSourceChange_addElementEdit(
- change,
- unitElement,
- new SourceEdit(target.offset, expr.offset - target.offset,
- '{' + eol + declStatement + exprStatement));
+ {
+ String code = '{' + eol + prefix + indent;
+ addPosition(
+ target.offset + code.length + nameOffsetInDeclarationCode);
+ code += declarationCode + eol;
+ code += prefix + indent + 'return ';
+ SourceEdit edit =
+ new SourceEdit(target.offset, expr.offset - target.offset, code);
+ occurrencesShift = target.offset + code.length - expr.offset;
+ doSourceChange_addElementEdit(change, unitElement, edit);
+ }
doSourceChange_addElementEdit(change, unitElement,
new SourceEdit(expr.end, 0, ';' + eol + prefix + '}'));
}
@@ -165,12 +184,23 @@
String occurrenceReplacement = name;
if (stringLiteralPart != null) {
occurrenceReplacement = "\${$name}";
+ occurrencesShift += 2;
}
// replace occurrences with variable reference
for (SourceRange range in occurrences) {
SourceEdit edit = newSourceEdit_range(range, occurrenceReplacement);
+ addPosition(range.offset + occurrencesShift);
+ occurrencesShift += name.length - range.length;
doSourceChange_addElementEdit(change, unitElement, edit);
}
+ // add the linked group
+ change.addLinkedEditGroup(new LinkedEditGroup(
+ positions,
+ name.length,
+ names
+ .map((name) => new LinkedEditSuggestion(
+ name, LinkedEditSuggestionKind.VARIABLE))
+ .toList()));
// done
return new Future.value(change);
}
@@ -194,8 +224,9 @@
selectionRange = new SourceRange(offset, end - offset);
}
// get covering node
- AstNode coveringNode = new NodeLocator(
- selectionRange.offset, selectionRange.end).searchWithin(unit);
+ AstNode coveringNode =
+ new NodeLocator(selectionRange.offset, selectionRange.end)
+ .searchWithin(unit);
// compute covering expressions
for (AstNode node = coveringNode;
node is Expression || node is ArgumentList;
diff --git a/pkg/analysis_server/lib/src/status/element_writer.dart b/pkg/analysis_server/lib/src/status/element_writer.dart
index fd73cef..24c922d 100644
--- a/pkg/analysis_server/lib/src/status/element_writer.dart
+++ b/pkg/analysis_server/lib/src/status/element_writer.dart
@@ -7,7 +7,7 @@
import 'dart:collection';
import 'dart:convert';
-import 'package:analysis_server/src/get_handler.dart';
+import 'package:analysis_server/src/status/get_handler.dart';
import 'package:analysis_server/src/status/tree_writer.dart';
import 'package:analyzer/src/generated/element.dart';
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 05937c0..23126f9 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -24,14 +24,15 @@
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/status/validator.dart';
import 'package:analysis_server/src/utilities/average.dart';
import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/source/error_processor.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
import 'package:analyzer/src/generated/ast.dart';
import 'package:analyzer/src/generated/element.dart';
-import 'package:analyzer/src/generated/engine.dart'
- hide AnalysisCache, AnalysisContextImpl, AnalysisTask;
+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/resolver.dart';
@@ -93,6 +94,17 @@
static const String COMMUNICATION_PERFORMANCE_PATH = '/perf/communication';
/**
+ * The path used to request diagnostic information for a single context.
+ */
+ static const String CONTEXT_DIAGNOSTICS_PATH = '/diagnostic/context';
+
+ /**
+ * The path used to request running a validation report for a single context.
+ */
+ static const String CONTEXT_VALIDATION_DIAGNOSTICS_PATH =
+ '/diagnostic/contextValidation';
+
+ /**
* The path used to request information about a specific context.
*/
static const String CONTEXT_PATH = '/context';
@@ -221,7 +233,7 @@
*/
void handleGetRequest(HttpRequest request) {
String path = request.uri.path;
- if (path == STATUS_PATH) {
+ if (path == '/' || path == STATUS_PATH) {
_returnServerStatus(request);
} else if (path == ANALYSIS_PERFORMANCE_PATH) {
_returnAnalysisPerformance(request);
@@ -235,6 +247,10 @@
_returnCompletionInfo(request);
} else if (path == COMMUNICATION_PERFORMANCE_PATH) {
_returnCommunicationPerformance(request);
+ } else if (path == CONTEXT_DIAGNOSTICS_PATH) {
+ _returnContextDiagnostics(request);
+ } else if (path == CONTEXT_VALIDATION_DIAGNOSTICS_PATH) {
+ _returnContextValidationDiagnostics(request);
} else if (path == CONTEXT_PATH) {
_returnContextInfo(request);
} else if (path == DIAGNOSTIC_PATH) {
@@ -973,6 +989,34 @@
}
/**
+ * Return a response displaying diagnostic information for a single context.
+ */
+ void _returnContextDiagnostics(HttpRequest request) {
+ AnalysisServer analysisServer = _server.analysisServer;
+ if (analysisServer == null) {
+ return _returnFailure(request, 'Analysis server is not running');
+ }
+ String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
+ if (contextFilter == null) {
+ return _returnFailure(
+ request, 'Query parameter $CONTEXT_QUERY_PARAM required');
+ }
+ Folder folder = _findFolder(analysisServer, contextFilter);
+ if (folder == null) {
+ return _returnFailure(request, 'Invalid context: $contextFilter');
+ }
+
+ InternalAnalysisContext context = analysisServer.folderMap[folder];
+
+ _writeResponse(request, (StringBuffer buffer) {
+ _writePage(buffer, 'Analysis Server - Context Diagnostics',
+ ['Context: $contextFilter'], (StringBuffer buffer) {
+ _writeContextDiagnostics(buffer, context);
+ });
+ });
+ }
+
+ /**
* Return a response containing information about a single source file in the
* cache.
*/
@@ -1032,9 +1076,6 @@
explicitNames.sort();
implicitNames.sort();
- AnalysisDriver driver = (context as AnalysisContextImpl).driver;
- List<WorkItem> workItems = driver.currentWorkOrder?.workItems;
-
_overlayContents.clear();
context.visitContentCache((String fullName, int stamp, String contents) {
_overlayContents[fullName] = contents;
@@ -1065,69 +1106,54 @@
_writePage(
buffer, 'Analysis Server - Context', ['Context: $contextFilter'],
(StringBuffer buffer) {
- buffer.write('<h3>Most Recently Perfomed Tasks</h3>');
- AnalysisTask.LAST_TASKS.forEach((String description) {
- buffer.write('<p>$description</p>');
- });
-
- String _describe(WorkItem item) {
- if (item == null) {
- return 'None';
- }
- return '${item.descriptor?.name} computing ${item.spawningResult?.name} for ${item.target?.toString()}';
- }
-
- buffer.write('<h3>Work Items</h3>');
- buffer.write(
- '<p><b>Current:</b> ${_describe(driver.currentWorkOrder?.current)}</p>');
- if (workItems != null) {
- buffer.writeAll(workItems.reversed
- .map((item) => '<p>${_describe(item)}</p>')
- ?.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>');
+ _writeTwoColumns(buffer, (StringBuffer buffer) {
+ 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>');
+ }, (StringBuffer buffer) {
+ 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>');
+ buffer.write(lint.runtimeType);
+ buffer.write('</p>');
+ }
}
- }
- List<ErrorFilter> errorFilters =
- context.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- int filterCount = errorFilters?.length ?? 0;
- buffer.write('<p><b>Error Filter count</b>: $filterCount</p>');
+ List<ErrorProcessor> errorProcessors =
+ context.getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
+ int processorCount = errorProcessors?.length ?? 0;
+ buffer.write('<p><b>Error Processor count</b>: $processorCount</p>');
+ });
_writeFiles(buffer, 'Priority Files', priorityNames);
_writeFiles(buffer, 'Explicitly Analyzed Files', explicitNames);
@@ -1135,12 +1161,59 @@
buffer.write('<h3>Exceptions</h3>');
if (exceptions.isEmpty) {
- buffer.write('<p>None</p>');
+ buffer.write('<p>none</p>');
} else {
exceptions.forEach((CaughtException exception) {
_writeException(buffer, exception);
});
}
+
+ buffer.write('<h3>Targets Without Entries</h3>');
+ bool foundEntry = false;
+ MapIterator<AnalysisTarget, CacheEntry> iterator =
+ context.analysisCache.iterator(context: context);
+ while (iterator.moveNext()) {
+ if (iterator.value == null) {
+ foundEntry = true;
+ buffer.write('<p>');
+ buffer.write(iterator.key.toString());
+ buffer.write(' (');
+ buffer.write(iterator.key.runtimeType.toString());
+ buffer.write(')</p>');
+ }
+ }
+ if (!foundEntry) {
+ buffer.write('<p>none</p>');
+ }
+ });
+ });
+ }
+
+ /**
+ * Return a response displaying the results of running a validation report on
+ * a single context.
+ */
+ void _returnContextValidationDiagnostics(HttpRequest request) {
+ AnalysisServer analysisServer = _server.analysisServer;
+ if (analysisServer == null) {
+ return _returnFailure(request, 'Analysis server is not running');
+ }
+ String contextFilter = request.uri.queryParameters[CONTEXT_QUERY_PARAM];
+ if (contextFilter == null) {
+ return _returnFailure(
+ request, 'Query parameter $CONTEXT_QUERY_PARAM required');
+ }
+ Folder folder = _findFolder(analysisServer, contextFilter);
+ if (folder == null) {
+ return _returnFailure(request, 'Invalid context: $contextFilter');
+ }
+
+ InternalAnalysisContext context = analysisServer.folderMap[folder];
+
+ _writeResponse(request, (StringBuffer buffer) {
+ _writePage(buffer, 'Analysis Server - Context Validation Diagnostics',
+ ['Context: $contextFilter'], (StringBuffer buffer) {
+ _writeContextValidationDiagnostics(buffer, context);
});
});
}
@@ -1149,8 +1222,6 @@
* 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) {
@@ -1332,23 +1403,19 @@
void _returnUnknownRequest(HttpRequest request) {
_writeResponse(request, (StringBuffer buffer) {
_writePage(buffer, 'Analysis Server', [], (StringBuffer buffer) {
- buffer.write('<h3>Pages</h3>');
- buffer.write('<p>');
- buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data'));
- buffer.write('</p>');
- buffer.write('<p>');
- buffer
- .write(makeLink(COMMUNICATION_PERFORMANCE_PATH, {}, 'Performance'));
- buffer.write('</p>');
- buffer.write('<p>');
- buffer.write(makeLink(STATUS_PATH, {}, 'Server status'));
- buffer.write('</p>');
- 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>');
+ buffer.write('<h3>Unknown page: ');
+ buffer.write(request.uri.path);
+ buffer.write('</h3>');
+ buffer.write('''
+ <p>
+ You have reached an un-recognized page. If you reached this page by
+ following a link from a status page, please report the broken link to
+ the Dart analyzer team:
+ <a>https://github.com/dart-lang/sdk/issues/new</a>.
+ </p><p>
+ If you mistyped the URL, you can correct it or return to
+ ${makeLink(STATUS_PATH, {}, 'the main status page')}.
+ </p>''');
});
});
}
@@ -1374,7 +1441,6 @@
List<Folder> folders = folderMap.keys.toList();
folders.sort((Folder first, Folder second) =>
first.shortName.compareTo(second.shortName));
- AnalysisOptionsImpl options = analysisServer.defaultContextOptions;
ServerOperationQueue operationQueue = analysisServer.operationQueue;
buffer.write('<h3>Analysis Domain</h3>');
@@ -1394,6 +1460,9 @@
buffer.write('<p>Status: Analyzing</p>');
}
}
+ buffer.write('<p>');
+ buffer.write(makeLink(OVERLAYS_PATH, {}, 'All overlay information'));
+ buffer.write('</p>');
buffer.write('<p><b>Analysis Contexts</b></p>');
buffer.write('<p>');
@@ -1407,8 +1476,12 @@
String key = folder.shortName;
buffer.write(makeLink(CONTEXT_PATH, {CONTEXT_QUERY_PARAM: folder.path},
key, _hasException(folderMap[folder])));
+ buffer.write(' <small><b>[');
+ buffer.write(makeLink(CONTEXT_DIAGNOSTICS_PATH,
+ {CONTEXT_QUERY_PARAM: folder.path}, 'diagnostics'));
+ buffer.write(']</b></small>');
if (!folder.getChild('.packages').exists) {
- buffer.write(' <b>[No .packages file]</b>');
+ buffer.write(' <small>[no .packages file]</small>');
}
});
// TODO(brianwilkerson) Add items for the SDK contexts (currently only one).
@@ -1416,9 +1489,9 @@
int freq = AnalysisServer.performOperationDelayFreqency;
String delay = freq > 0 ? '1 ms every $freq ms' : 'off';
- buffer.write('<p><b>perform operation delay:</b> $delay</p>');
buffer.write('<p><b>Performance Data</b></p>');
+ buffer.write('<p>Perform operation delay: $delay</p>');
buffer.write('<p>');
buffer.write(makeLink(ANALYSIS_PERFORMANCE_PATH, {}, 'Task data'));
buffer.write('</p>');
@@ -1531,6 +1604,70 @@
}
/**
+ * Write diagnostic information about the given [context] to the given
+ * [buffer].
+ */
+ void _writeContextDiagnostics(
+ StringBuffer buffer, InternalAnalysisContext context) {
+ AnalysisDriver driver = (context as AnalysisContextImpl).driver;
+ List<WorkItem> workItems = driver.currentWorkOrder?.workItems;
+
+ buffer.write('<p>');
+ buffer.write(makeLink(CONTEXT_VALIDATION_DIAGNOSTICS_PATH,
+ {CONTEXT_QUERY_PARAM: context.name}, 'Run validation'));
+ buffer.write('</p>');
+
+ buffer.write('<h3>Most Recently Perfomed Tasks</h3>');
+ AnalysisTask.LAST_TASKS.forEach((String description) {
+ buffer.write('<p>');
+ buffer.write(description);
+ buffer.write('</p>');
+ });
+
+ void writeWorkItem(StringBuffer buffer, WorkItem item) {
+ if (item == null) {
+ buffer.write('none');
+ } else {
+ buffer.write(item.descriptor?.name);
+ buffer.write(' computing ');
+ buffer.write(item.spawningResult?.name);
+ buffer.write(' for ');
+ buffer.write(item.target);
+ }
+ }
+
+ buffer.write('<h3>Work Items</h3>');
+ buffer.write('<p><b>Current:</b> ');
+ writeWorkItem(buffer, driver.currentWorkOrder?.current);
+ buffer.write('</p>');
+ if (workItems != null) {
+ workItems.reversed.forEach((WorkItem item) {
+ buffer.write('<p>');
+ writeWorkItem(buffer, item);
+ buffer.write('</p>');
+ });
+ }
+ }
+
+ /**
+ * Write diagnostic information about the given [context] to the given
+ * [buffer].
+ */
+ void _writeContextValidationDiagnostics(
+ StringBuffer buffer, InternalAnalysisContext context) {
+ Stopwatch stopwatch = new Stopwatch();
+ stopwatch.start();
+ ValidationResults results = new ValidationResults(context);
+ stopwatch.stop();
+
+ buffer.write('<h3>Validation Results</h3>');
+ buffer.write('<p>Re-analysis took ');
+ buffer.write(stopwatch.elapsedMilliseconds);
+ buffer.write(' ms</p>');
+ results.writeOn(buffer);
+ }
+
+ /**
* Write the status of the diagnostic domain to the given [buffer].
*/
void _writeDiagnosticStatus(StringBuffer buffer) {
@@ -1546,28 +1683,32 @@
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> ');
+ buffer.write('<p>getDiagnostic (last call): ');
+ buffer.write(elapsedMs);
+ buffer.write(' (ms)</p>');
+ buffer.write('<p>getDiagnostic (rolling average): ');
+ buffer.write(_diagnosticCallAverage.value);
+ buffer.write(' (ms)</p> ');
var json = response.toJson()[Response.RESULT];
List contexts = json['contexts'];
+ contexts.sort((first, second) => first['name'].compareTo(second['name']));
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> ');
+ buffer.write('<p><h3>');
+ buffer.write(context['name']);
+ buffer.write('</h3></p>');
+ buffer.write('<p>explicitFileCount: ');
+ buffer.write(context['explicitFileCount']);
+ buffer.write('</p>');
+ buffer.write('<p>implicitFileCount: ');
+ buffer.write(context['implicitFileCount']);
+ buffer.write('</p>');
+ buffer.write('<p>workItemQueueLength: ');
+ buffer.write(context['workItemQueueLength']);
+ buffer.write('</p>');
+ buffer.write('<p>workItemQueueLengthAverage: ');
+ buffer.write(context['workItemQueueLengthAverage']);
+ buffer.write('</p>');
}
}
@@ -1708,6 +1849,8 @@
buffer.write(
'h3 {background-color: #DDDDDD; margin-top: 0em; margin-bottom: 0em;}');
buffer.write('p {margin-top: 0.5em; margin-bottom: 0.5em;}');
+ buffer.write(
+ 'p.commentary {margin-top: 1em; margin-bottom: 1em; margin-left: 2em; font-style: italic;}');
// response.write('span.error {text-decoration-line: underline; text-decoration-color: red; text-decoration-style: wavy;}');
buffer.write(
'table.column {border: 0px solid black; width: 100%; table-layout: fixed;}');
@@ -1868,6 +2011,9 @@
buffer.write(makeLink(
COMMUNICATION_PERFORMANCE_PATH, {}, 'Communication performance'));
buffer.write('</p>');
+ buffer.write('<p>');
+ buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'General diagnostics'));
+ buffer.write('</p>');
}, (StringBuffer buffer) {
_writeSubscriptionList(buffer, ServerService.VALUES, services);
});
diff --git a/pkg/analysis_server/lib/src/status/tree_writer.dart b/pkg/analysis_server/lib/src/status/tree_writer.dart
index 4b5b3a4..c862a8b 100644
--- a/pkg/analysis_server/lib/src/status/tree_writer.dart
+++ b/pkg/analysis_server/lib/src/status/tree_writer.dart
@@ -2,11 +2,11 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library analysis_server.src.status.ast_writer;
+library analysis_server.src.status.tree_writer;
import 'dart:convert';
-import 'package:analysis_server/src/get_handler.dart';
+import 'package:analysis_server/src/status/get_handler.dart';
import 'package:analyzer/src/generated/constant.dart';
import 'package:analyzer/src/generated/element.dart';
import 'package:analyzer/src/generated/java_engine.dart';
diff --git a/pkg/analysis_server/lib/src/status/validator.dart b/pkg/analysis_server/lib/src/status/validator.dart
new file mode 100644
index 0000000..dccf996
--- /dev/null
+++ b/pkg/analysis_server/lib/src/status/validator.dart
@@ -0,0 +1,1787 @@
+// 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.status.validator;
+
+import 'dart:collection';
+
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/constant.dart';
+import 'package:analyzer/src/generated/element.dart';
+import 'package:analyzer/src/generated/engine.dart'
+ show AnalysisEngine, AnalysisResult, CacheState, ChangeSet;
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/scanner.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_collection.dart';
+import 'package:analyzer/src/task/dart.dart';
+import 'package:analyzer/src/task/html.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
+import 'package:html/dom.dart' as html;
+
+/**
+ * A class used to compare two element models for equality.
+ */
+class ElementComparator {
+ /**
+ * The buffer to which any discovered differences will be recorded.
+ */
+ final StringBuffer _buffer = new StringBuffer();
+
+ /**
+ * A flag indicating whether a line break should be added the next time data
+ * is written to the [_buffer].
+ */
+ bool _needsLineBreak = false;
+
+ /**
+ * Initialize a newly created comparator.
+ */
+ ElementComparator();
+
+ /**
+ * A textual description of the differences that were found.
+ */
+ String get description => _buffer.toString();
+
+ /**
+ * Return `true` if at least one difference was found between the expected and
+ * actual elements.
+ */
+ bool get hasDifference => _buffer.length > 0;
+
+ /**
+ * Compare the [expected] and [actual] elements. The results of the comparison
+ * can be accessed via the [hasDifference] and [description] getters.
+ */
+ void compareElements(Element expected, Element actual) {
+ if (expected == null) {
+ if (actual != null) {
+ _writeMismatch(expected, actual, (Element element) {
+ return element == null ? 'null' : 'non null ${element.runtimeType}';
+ });
+ }
+ } else if (actual == null) {
+ _writeMismatch(expected, actual, (Element element) {
+ return element == null ? 'null' : 'non null ${element.runtimeType}';
+ });
+ } else if (expected is ClassElement && actual is ClassElement) {
+ _compareClassElements(expected, actual);
+ } else if (expected is CompilationUnitElement &&
+ actual is CompilationUnitElement) {
+ _compareCompilationUnitElements(expected, actual);
+ } else if (expected is ConstructorElement && actual is ConstructorElement) {
+ _compareConstructorElements(expected, actual);
+ } else if (expected is ExportElement && actual is ExportElement) {
+ _compareExportElements(expected, actual);
+ } else if (expected is FieldElement && actual is FieldElement) {
+ _compareFieldElements(expected, actual);
+ } else if (expected is FieldFormalParameterElement &&
+ actual is FieldFormalParameterElement) {
+ _compareFieldFormalParameterElements(expected, actual);
+ } else if (expected is FunctionElement && actual is FunctionElement) {
+ _compareFunctionElements(expected, actual);
+ } else if (expected is FunctionTypeAliasElement &&
+ actual is FunctionTypeAliasElement) {
+ _compareFunctionTypeAliasElements(expected, actual);
+ } else if (expected is ImportElement && actual is ImportElement) {
+ _compareImportElements(expected, actual);
+ } else if (expected is LabelElement && actual is LabelElement) {
+ _compareLabelElements(expected, actual);
+ } else if (expected is LibraryElement && actual is LibraryElement) {
+ _compareLibraryElements(expected, actual);
+ } else if (expected is LocalVariableElement &&
+ actual is LocalVariableElement) {
+ _compareLocalVariableElements(expected, actual);
+ } else if (expected is MethodElement && actual is MethodElement) {
+ _compareMethodElements(expected, actual);
+ } else if (expected is MultiplyDefinedElement &&
+ actual is MultiplyDefinedElement) {
+ _compareMultiplyDefinedElements(expected, actual);
+ } else if (expected is ParameterElement && actual is ParameterElement) {
+ _compareParameterElements(expected, actual);
+ } else if (expected is PrefixElement && actual is PrefixElement) {
+ _comparePrefixElements(expected, actual);
+ } else if (expected is PropertyAccessorElement &&
+ actual is PropertyAccessorElement) {
+ _comparePropertyAccessorElements(expected, actual);
+ } else if (expected is TopLevelVariableElement &&
+ actual is TopLevelVariableElement) {
+ _compareTopLevelVariableElements(expected, actual);
+ } else if (expected is TypeParameterElement &&
+ actual is TypeParameterElement) {
+ _compareTypeParameterElements(expected, actual);
+ } else {
+ _write('Expected an instance of ');
+ _write(expected.runtimeType);
+ _write('; found an instance of ');
+ _writeln(actual.runtimeType);
+ }
+ }
+
+ void _compareClassElements(ClassElement expected, ClassElement actual) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if (expected.hasReferenceToSuper != actual.hasReferenceToSuper) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ClassElement element) => element.hasReferenceToSuper
+ ? 'a class that references super'
+ : 'a class that does not reference super');
+ }
+ if (expected.isAbstract != actual.isAbstract) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ClassElement element) =>
+ element.isAbstract ? 'an abstract class' : 'a concrete class');
+ }
+ if (expected.isEnum != actual.isEnum ||
+ expected.isMixinApplication != actual.isMixinApplication) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ClassElement element) => element.isEnum
+ ? 'an enum'
+ : (element.isMixinApplication
+ ? 'a mixin application'
+ : 'a class'));
+ }
+ if (expected.isOrInheritsProxy != actual.isOrInheritsProxy) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ClassElement element) => element.isOrInheritsProxy
+ ? 'a class that is marked as a proxy'
+ : 'a class that is not marked as a proxy');
+ }
+ if (expected.isValidMixin != actual.isValidMixin) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ClassElement element) =>
+ element.isValidMixin ? 'a valid mixin' : 'an invalid mixin');
+ }
+ _compareTypes('supertype', expected.supertype, actual.supertype);
+ _compareTypeLists('mixin', expected.mixins, actual.mixins);
+ _compareTypeLists('interface', expected.interfaces, actual.interfaces);
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.accessors, actual.accessors);
+ _compareElementLists(expected.constructors, actual.constructors);
+ _compareElementLists(expected.fields, actual.fields);
+ _compareElementLists(expected.methods, actual.methods);
+ _compareElementLists(expected.typeParameters, actual.typeParameters);
+ }
+
+ void _compareCompilationUnitElements(
+ CompilationUnitElement expected, CompilationUnitElement actual) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.accessors, actual.accessors);
+ _compareElementLists(expected.enums, actual.enums);
+ _compareElementLists(expected.functions, actual.functions);
+ _compareElementLists(
+ expected.functionTypeAliases, actual.functionTypeAliases);
+ _compareElementLists(expected.topLevelVariables, actual.topLevelVariables);
+ _compareElementLists(expected.types, actual.types);
+ }
+
+ void _compareConstructorElements(
+ ConstructorElement expected, ConstructorElement actual) {
+ _compareExecutableElements(expected, actual, 'constructor');
+ //
+ // Compare attributes.
+ //
+ if (expected.isConst != actual.isConst) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ConstructorElement element) => element.isConst
+ ? 'a const constructor'
+ : 'a non-const constructor');
+ }
+ if (expected.isFactory != actual.isFactory) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ConstructorElement element) => element.isFactory
+ ? 'a factory constructor'
+ : 'a non-factory constructor');
+ }
+ if (expected.periodOffset != actual.periodOffset) {
+ _write('Expected a period offset of ');
+ _write(expected.periodOffset);
+ _write('; found ');
+ _writeln(actual.periodOffset);
+ }
+ if ((expected.redirectedConstructor == null) !=
+ (actual.redirectedConstructor == null)) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ConstructorElement element) => element.redirectedConstructor == null
+ ? 'a redirecting constructor'
+ : 'a non-redirecting constructor');
+ }
+ }
+
+ void _compareElementLists(List expected, List actual) {
+ Set<Element> extraElements = new HashSet<Element>();
+ Map<Element, Element> commonElements = new HashMap<Element, Element>();
+
+ Map<String, Element> expectedElements = new HashMap<String, Element>();
+ for (Element expectedElement in expected) {
+ expectedElements[expectedElement.name] = expectedElement;
+ }
+ for (Element actualElement in actual) {
+ String name = actualElement.name;
+ Element expectedElement = expectedElements[name];
+ if (expectedElement == null) {
+ extraElements.add(actualElement);
+ } else {
+ commonElements[expectedElement] = actualElement;
+ expectedElements.remove(name);
+ }
+ }
+
+ commonElements.forEach((Element expected, Element actual) {
+ compareElements(expected, actual);
+ });
+ void writeElement(Element element) {
+ _write('an instance of ');
+ _write(element.runtimeType);
+ if (element.name == null) {
+ _write(' with no name');
+ } else {
+ _write(' named ');
+ _write(element.name);
+ }
+ }
+ expectedElements.forEach((String name, Element element) {
+ _write('Expected ');
+ writeElement(element);
+ _writeln('; found no match');
+ });
+ extraElements.forEach((Element element) {
+ _write('Expected nothing; found ');
+ writeElement(element);
+ });
+ }
+
+ void _compareExecutableElements(
+ ExecutableElement expected, ExecutableElement actual, String kind) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if (expected.hasImplicitReturnType != actual.hasImplicitReturnType) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) => element.hasImplicitReturnType
+ ? 'an implicit return type'
+ : 'an explicit return type');
+ }
+ if (expected.isAbstract != actual.isAbstract) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) =>
+ element.isAbstract ? 'an abstract $kind' : 'a concrete $kind');
+ }
+ if (expected.isAsynchronous != actual.isAsynchronous) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) => element.isAsynchronous
+ ? 'an asynchronous $kind'
+ : 'a synchronous $kind');
+ }
+ if (expected.isExternal != actual.isExternal) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) => element.isExternal
+ ? 'an external $kind'
+ : 'a non-external $kind');
+ }
+ if (expected.isGenerator != actual.isGenerator) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) => element.isGenerator
+ ? 'a generator $kind'
+ : 'a non-generator $kind');
+ }
+ if (expected.isOperator != actual.isOperator) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) =>
+ element.isOperator ? 'an operator' : 'a non-operator $kind');
+ }
+ if (expected.isStatic != actual.isStatic) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) =>
+ element.isStatic ? 'a static $kind' : 'an instance $kind');
+ }
+ if ((expected.returnType == null) != (actual.returnType == null)) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ExecutableElement element) => element.returnType == null
+ ? 'a $kind with no return type'
+ : 'a $kind with a return type');
+ } else {
+ _compareTypes('return type', expected.returnType, actual.returnType);
+ }
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.functions, actual.functions);
+ _compareElementLists(expected.labels, actual.labels);
+ _compareElementLists(expected.localVariables, actual.localVariables);
+ _compareElementLists(expected.parameters, actual.parameters);
+ _compareElementLists(expected.typeParameters, actual.typeParameters);
+ }
+
+ void _compareExportElements(ExportElement expected, ExportElement actual) {
+ _compareUriReferencedElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if ((expected.exportedLibrary == null) !=
+ (actual.exportedLibrary == null)) {
+ // TODO(brianwilkerson) Check for more than existence?
+ _writeMismatch(
+ expected,
+ actual,
+ (ExportElement element) => element.exportedLibrary == null
+ ? 'unresolved uri'
+ : 'uri resolved to ${element.exportedLibrary.source.fullName}');
+ }
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.combinators, actual.combinators);
+ }
+
+ void _compareFieldElements(FieldElement expected, FieldElement actual) {
+ _comparePropertyInducingElements(expected, actual, 'field');
+ //
+ // Compare attributes.
+ //
+ if (expected.isEnumConstant != actual.isEnumConstant) {
+ _writeMismatch(
+ expected,
+ actual,
+ (FieldElement element) =>
+ element.isEnumConstant ? 'an enum constant' : 'a normal field');
+ }
+ }
+
+ void _compareFieldFormalParameterElements(
+ FieldFormalParameterElement expected,
+ FieldFormalParameterElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareFunctionElements(
+ FunctionElement expected, FunctionElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareFunctionTypeAliasElements(
+ FunctionTypeAliasElement expected, FunctionTypeAliasElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareGenericElements(Element expected, Element actual) {
+ _compareMetadata(expected.metadata, actual.metadata);
+ if (expected.nameOffset != actual.nameOffset) {
+ _write('Expected name offset of ');
+ _write(expected.nameOffset);
+ _write('; found ');
+ _writeln(actual.nameOffset);
+ }
+ SourceRange expectedRange = expected.docRange;
+ SourceRange actualRange = actual.docRange;
+ if (expectedRange.offset != actualRange.offset ||
+ expectedRange.length != actualRange.length) {
+ _write('Expected documentation range of ');
+ _write(expectedRange);
+ _write('; found ');
+ _writeln(actualRange);
+ }
+ }
+
+ void _compareImportElements(ImportElement expected, ImportElement actual) {
+ _compareUriReferencedElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if (expected.isDeferred != actual.isDeferred) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ImportElement element) => element.isDeferred
+ ? 'a deferred import'
+ : 'a non-deferred import');
+ }
+ if ((expected.importedLibrary == null) !=
+ (actual.importedLibrary == null)) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ImportElement element) => element.importedLibrary == null
+ ? 'unresolved uri'
+ : 'uri resolved to ${element.importedLibrary.source.fullName}');
+ }
+ if ((expected.prefix == null) != (actual.prefix == null)) {
+ _writeMismatch(
+ expected,
+ actual,
+ (ImportElement element) => element.prefix == null
+ ? 'no prefix'
+ : 'a prefix named ${element.prefix.name}');
+ }
+ if (expected.prefixOffset != actual.prefixOffset) {
+ _write('Expected a prefix offset of ');
+ _write(expected.prefixOffset);
+ _write('; found ');
+ _writeln(actual.prefixOffset);
+ }
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.combinators, actual.combinators);
+ }
+
+ void _compareLabelElements(LabelElement expected, LabelElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareLibraryElements(LibraryElement expected, LibraryElement actual) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ // TODO(brianwilkerson) Implement this
+ expected.hasLoadLibraryFunction;
+ expected.name;
+ expected.source;
+ //
+ // Compare children.
+ //
+ _compareElementLists(expected.imports, actual.imports);
+ _compareElementLists(expected.exports, actual.exports);
+ _compareElementLists(expected.units, actual.units);
+ }
+
+ void _compareLocalVariableElements(
+ LocalVariableElement expected, LocalVariableElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareMetadata(
+ List<ElementAnnotation> expected, List<ElementAnnotation> actual) {
+ // TODO(brianwilkerson) Implement this
+ }
+
+ void _compareMethodElements(MethodElement expected, MethodElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareExecutableElements(expected, actual, 'method');
+ //
+ // Compare attributes.
+ //
+ if (expected.isStatic != actual.isStatic) {
+ _writeMismatch(
+ expected,
+ actual,
+ (FieldElement element) =>
+ element.isStatic ? 'a static field' : 'an instance field');
+ }
+ }
+
+ void _compareMultiplyDefinedElements(
+ MultiplyDefinedElement expected, MultiplyDefinedElement actual) {
+ // TODO(brianwilkerson) Implement this
+ }
+
+ void _compareParameterElements(
+ ParameterElement expected, ParameterElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _comparePrefixElements(PrefixElement expected, PrefixElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _comparePropertyAccessorElements(
+ PropertyAccessorElement expected, PropertyAccessorElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _comparePropertyInducingElements(PropertyInducingElement expected,
+ PropertyInducingElement actual, String kind) {
+ _compareVariableElements(expected, actual, kind);
+ }
+
+ void _compareTopLevelVariableElements(
+ TopLevelVariableElement expected, TopLevelVariableElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ }
+
+ void _compareTypeLists(String descriptor, List<InterfaceType> expected,
+ List<InterfaceType> actual) {
+ int expectedLength = expected.length;
+ if (expectedLength != actual.length) {
+ _write('Expected ');
+ _write(expectedLength);
+ _write(' ');
+ _write(descriptor);
+ _write('s; found ');
+ _write(actual.length);
+ } else {
+ for (int i = 0; i < expectedLength; i++) {
+ _compareTypes(descriptor, expected[i], actual[i]);
+ }
+ }
+ }
+
+ void _compareTypeParameterElements(
+ TypeParameterElement expected, TypeParameterElement actual) {
+ // TODO(brianwilkerson) Implement this
+ _compareGenericElements(expected, actual);
+ expected.bound;
+ }
+
+ void _compareTypes(String descriptor, DartType expected, DartType actual) {
+ void compareNames() {
+ if (expected.name != actual.name) {
+ _write('Expected a ');
+ _write(descriptor);
+ _write(' named ');
+ _write(expected.name);
+ _write('; found a ');
+ _write(descriptor);
+ _write(' named ');
+ _write(actual.name);
+ }
+ }
+ void compareTypeArguments(
+ ParameterizedType expected, ParameterizedType actual) {
+ List<DartType> expectedArguments = expected.typeArguments;
+ List<DartType> actualArguments = actual.typeArguments;
+ int expectedLength = expectedArguments.length;
+ if (expectedLength != actualArguments.length) {
+ _write('Expected ');
+ _write(expectedLength);
+ _write(' type arguments; found ');
+ _write(actualArguments.length);
+ } else {
+ for (int i = 0; i < expectedLength; i++) {
+ _compareTypes(
+ 'type argument', expectedArguments[i], actualArguments[i]);
+ }
+ }
+ }
+
+ if (expected == null) {
+ if (actual != null) {
+ _write('Expected no ');
+ _write(descriptor);
+ _write('; found a ');
+ _write(descriptor);
+ _write(' named ');
+ _write(actual.name);
+ }
+ } else if (actual == null) {
+ _write('Expected a ');
+ _write(descriptor);
+ _write(' named ');
+ _write(expected.name);
+ _write('; found none');
+ } else if ((expected.isBottom && actual.isBottom) ||
+ (expected.isDynamic && actual.isDynamic) ||
+ (expected.isVoid && actual.isVoid)) {
+ // The types are the same
+ } else if (expected is InterfaceType && actual is InterfaceType) {
+ compareNames();
+ compareTypeArguments(expected, actual);
+ } else if (expected is FunctionType && actual is FunctionType) {
+ compareNames();
+ compareTypeArguments(expected, actual);
+ } else if (expected is TypeParameterType && actual is TypeParameterType) {
+ compareNames();
+ _compareTypes('bound', expected.element.bound, actual.element.bound);
+ } else {
+ _write('Expected an instance of ');
+ _write(expected.runtimeType);
+ _write(' named ');
+ _write(expected.name);
+ _write('; found an instance of ');
+ _writeln(actual.runtimeType);
+ _write(' named ');
+ _write(actual.name);
+ }
+ }
+
+ void _compareUriReferencedElements(
+ UriReferencedElement expected, UriReferencedElement actual) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if (expected.uri != actual.uri) {
+ _write('Expected a uri of ');
+ _write(expected.uri);
+ _write('; found ');
+ _writeln(actual.uri);
+ }
+ if (expected.uriOffset != actual.uriOffset) {
+ _write('Expected a uri offset of ');
+ _write(expected.uriOffset);
+ _write('; found ');
+ _writeln(actual.uriOffset);
+ }
+ }
+
+ void _compareVariableElements(
+ VariableElement expected, VariableElement actual, String kind) {
+ _compareGenericElements(expected, actual);
+ //
+ // Compare attributes.
+ //
+ if ((expected.constantValue == null) != (actual.constantValue == null)) {
+ // TODO(brianwilkerson) Check for more than existence.
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) => element.constantValue == null
+ ? 'a $kind with no constant value'
+ : 'a $kind with a constant value');
+ }
+ if (expected.hasImplicitType != actual.hasImplicitType) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) => element.hasImplicitType
+ ? 'a $kind with an implicit type'
+ : 'a $kind with an explicit type');
+ }
+ if (expected.isConst != actual.isConst) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) =>
+ element.isConst ? 'a const $kind' : 'a non-const $kind');
+ }
+ if (expected.isFinal != actual.isFinal) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) =>
+ element.isFinal ? 'a final $kind' : 'a non-final $kind');
+ }
+ if (expected.isPotentiallyMutatedInClosure !=
+ actual.isPotentiallyMutatedInClosure) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) => element.isPotentiallyMutatedInClosure
+ ? 'a $kind that is potentially mutated in a closure'
+ : 'a $kind that is not mutated in a closure');
+ }
+ if (expected.isPotentiallyMutatedInScope !=
+ actual.isPotentiallyMutatedInScope) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) => element.isPotentiallyMutatedInScope
+ ? 'a $kind that is potentially mutated in its scope'
+ : 'a $kind that is not mutated in its scope');
+ }
+ if (expected.isStatic != actual.isStatic) {
+ _writeMismatch(
+ expected,
+ actual,
+ (VariableElement element) =>
+ element.isStatic ? 'a static $kind' : 'an instance $kind');
+ }
+ //
+ // Compare children.
+ //
+ compareElements(expected.initializer, actual.initializer);
+ }
+
+ void _write(Object value) {
+ if (_needsLineBreak) {
+ _buffer.write('</p><p>');
+ _needsLineBreak = false;
+ }
+ _buffer.write(value);
+ }
+
+ void _writeln(Object value) {
+ _buffer.write(value);
+ _needsLineBreak = true;
+ }
+
+ /**
+ * Write a simple message explaining that the [expected] and [actual] values
+ * were different, using the [describe] function to describe the values.
+ */
+ void _writeMismatch /*<E>*/ (Object /*=E*/ expected, Object /*=E*/ actual,
+ String describe(Object /*=E*/ value)) {
+ _write('Expected ');
+ _write(describe(expected));
+ _write('; found ');
+ _writeln(describe(actual));
+ }
+}
+
+/**
+ * The comparison of two analyses of the same target.
+ */
+class EntryComparison {
+ /**
+ * The target that was analyzed.
+ */
+ final AnalysisTarget target;
+
+ /**
+ * The cache entry from the original context.
+ */
+ final CacheEntry originalEntry;
+
+ /**
+ * The cache entry from the re-analysis in a cloned context.
+ */
+ final CacheEntry cloneEntry;
+
+ /**
+ * A flag indicating whether the target is obsolete. A target is obsolete if
+ * it is an element in an element model that was replaced at a some point.
+ */
+ bool obsoleteTarget = false;
+
+ /**
+ * A table mapping the results that were computed for the target to
+ * comparisons of the values of those results. The table only contains entries
+ * for results for which the comparison produced interesting data.
+ */
+ Map<ResultDescriptor, ResultComparison> resultMap =
+ new HashMap<ResultDescriptor, ResultComparison>();
+
+ /**
+ * Initialize a newly created comparison of the given [target]'s analysis,
+ * given the [originalEntry] from the original context and the [cloneEntry]
+ * from the cloned context.
+ */
+ EntryComparison(this.target, this.originalEntry, this.cloneEntry) {
+ _performComparison();
+ }
+
+ /**
+ * Return `true` if there is something interesting about the analysis of this
+ * target that should be reported.
+ */
+ bool hasInterestingState() => obsoleteTarget || resultMap.isNotEmpty;
+
+ /**
+ * Write an HTML formatted description of the validation results to the given
+ * [buffer].
+ */
+ void writeOn(StringBuffer buffer) {
+ buffer.write('<p>');
+ buffer.write(target);
+ buffer.write('</p>');
+ buffer.write('<blockquote>');
+ if (obsoleteTarget) {
+ buffer.write('<p><b>This target is obsolete.</b></p>');
+ }
+ List<ResultDescriptor> results = resultMap.keys.toList();
+ results.sort((ResultDescriptor first, ResultDescriptor second) =>
+ first.toString().compareTo(second.toString()));
+ for (ResultDescriptor result in results) {
+ resultMap[result].writeOn(buffer);
+ }
+ buffer.write('</blockquote>');
+ }
+
+ /**
+ * Compare all of the results that were computed in the two contexts, adding
+ * the interesting comparisons to the [resultMap].
+ */
+ void _compareResults() {
+ Set<ResultDescriptor> results = new Set<ResultDescriptor>();
+ results.addAll(originalEntry.nonInvalidResults);
+ results.addAll(cloneEntry.nonInvalidResults);
+
+ for (ResultDescriptor result in results) {
+ ResultComparison difference = new ResultComparison(this, result);
+ if (difference.hasInterestingState()) {
+ resultMap[result] = difference;
+ }
+ }
+ }
+
+ /**
+ * Return `true` if the target of this entry is an obsolete element.
+ */
+ bool _isTargetObsolete() {
+ if (target is Element) {
+ LibraryElement library = (target as Element).library;
+ AnalysisContextImpl context = library.context;
+ CacheEntry entry = context.analysisCache.get(library.source);
+ LibraryElement value = entry.getValue(LIBRARY_ELEMENT);
+ return value != library;
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether or not there is any interesting difference between the
+ * original and cloned contexts.
+ */
+ void _performComparison() {
+ obsoleteTarget = _isTargetObsolete();
+ _compareResults();
+ }
+}
+
+/**
+ * The comparison of the value of a single result computed for a single target.
+ */
+class ResultComparison {
+ /**
+ * The entry for the target for which the result was computed.
+ */
+ final EntryComparison entry;
+
+ /**
+ * The result that was computed for the target.
+ */
+ final ResultDescriptor result;
+
+ /**
+ * A flag indicating whether the state of the result is different.
+ */
+ bool differentStates = false;
+
+ /**
+ * The result of comparing the values of the results, or `null` if the states
+ * are different or if the values are the same.
+ */
+ ValueComparison valueComparison;
+
+ /**
+ * Initialize a newly created result comparison.
+ */
+ ResultComparison(this.entry, this.result) {
+ _performComparison();
+ }
+
+ /**
+ * Return `true` if this object represents a difference between the original
+ * and cloned contexts.
+ */
+ bool hasInterestingState() => differentStates || valueComparison != null;
+
+ /**
+ * Write an HTML formatted description of the validation results to the given
+ * [buffer].
+ */
+ void writeOn(StringBuffer buffer) {
+ buffer.write('<p>');
+ buffer.write(result);
+ buffer.write('</p>');
+ buffer.write('<blockquote>');
+ if (differentStates) {
+ CacheState originalState = entry.originalEntry.getState(result);
+ CacheState cloneState = entry.cloneEntry.getState(result);
+ buffer.write('<p>Original state = ');
+ buffer.write(originalState.name);
+ buffer.write('; clone state = ');
+ buffer.write(cloneState.name);
+ buffer.write('</p>');
+ }
+ if (valueComparison != null) {
+ valueComparison.writeOn(buffer);
+ }
+ buffer.write('</blockquote>');
+ }
+
+ /**
+ * Determine whether the state of the result is different between the
+ * original and cloned contexts.
+ */
+ bool _areStatesDifferent(CacheState originalState, CacheState cloneState) {
+ if (originalState == cloneState) {
+ return false;
+ } else if (originalState == CacheState.FLUSHED &&
+ cloneState == CacheState.VALID) {
+ return false;
+ } else if (originalState == CacheState.VALID &&
+ cloneState == CacheState.FLUSHED) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determine whether the value of the result is different between the
+ * original and cloned contexts.
+ */
+ void _compareValues(CacheState originalState, CacheState cloneState) {
+ if (originalState != cloneState || originalState != CacheState.VALID) {
+ return null;
+ }
+ ValueComparison comparison = new ValueComparison(
+ entry.originalEntry.getValue(result),
+ entry.cloneEntry.getValue(result));
+ if (comparison.hasInterestingState()) {
+ valueComparison = comparison;
+ }
+ }
+
+ /**
+ * Determine whether or not there is any interesting difference between the
+ * original and cloned contexts.
+ */
+ void _performComparison() {
+ CacheState originalState = entry.originalEntry.getState(result);
+ CacheState cloneState = entry.cloneEntry.getState(result);
+ if (_areStatesDifferent(originalState, cloneState)) {
+ differentStates = true;
+ _compareValues(originalState, cloneState);
+ }
+ }
+}
+
+/**
+ * The results of validating an analysis context.
+ *
+ * Validation is done by re-analyzing all of the explicitly added source in a
+ * new analysis context that is configured to be the same as the original
+ * context.
+ */
+class ValidationResults {
+ /**
+ * A set of targets that were in the original context that were not included
+ * in the re-created context.
+ */
+ Set<AnalysisTarget> extraTargets;
+
+ /**
+ * A set of targets that were in the re-created context that were not included
+ * in the original context.
+ */
+ Set<AnalysisTarget> missingTargets;
+
+ /**
+ * A table, keyed by targets, whose values are comparisons of the analysis of
+ * those targets. The table only contains entries for targets for which the
+ * comparison produced interesting data.
+ */
+ Map<AnalysisTarget, EntryComparison> targetMap =
+ new HashMap<AnalysisTarget, EntryComparison>();
+
+ /**
+ * Initialize a newly created validation result by validating the given
+ * [context].
+ */
+ ValidationResults(AnalysisContextImpl context) {
+ _validate(context);
+ }
+
+ /**
+ * Write an HTML formatted description of the validation results to the given
+ * [buffer].
+ */
+ void writeOn(StringBuffer buffer) {
+ if (extraTargets.isEmpty && missingTargets.isEmpty && targetMap.isEmpty) {
+ buffer.write('<p>No interesting results.</p>');
+ return;
+ }
+ if (extraTargets.isNotEmpty) {
+ buffer.write('<h4>Extra Targets</h4>');
+ buffer.write('<p style="commentary">');
+ buffer.write('Targets that exist in the original context that were not ');
+ buffer.write('re-created in the cloned context.');
+ buffer.write('</p>');
+ _writeTargetList(buffer, extraTargets.toList());
+ }
+ if (missingTargets.isNotEmpty) {
+ buffer.write('<h4>Missing Targets</h4>');
+ buffer.write('<p style="commentary">');
+ buffer.write('Targets that do <b>not</b> exist in the original context ');
+ buffer.write('but do exist in the cloned context.');
+ buffer.write('</p>');
+ _writeTargetList(buffer, missingTargets.toList());
+ }
+ if (targetMap.isNotEmpty) {
+ buffer.write('<h4>Differing Targets</h4>');
+ // TODO(brianwilkerson) Sort the list of targets.
+ for (EntryComparison comparison in targetMap.values) {
+ comparison.writeOn(buffer);
+ }
+ }
+ }
+
+ /**
+ * Analyze all of the explicit sources in the given [context].
+ */
+ void _analyze(AnalysisContextImpl context) {
+ while (true) {
+ AnalysisResult result = context.performAnalysisTask();
+ if (!result.hasMoreWork) {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Create and return a new analysis context that will analyze files in the
+ * same way as the given [context].
+ */
+ AnalysisContextImpl _clone(AnalysisContextImpl context) {
+ AnalysisContextImpl clone = AnalysisEngine.instance.createAnalysisContext();
+
+ clone.analysisOptions = context.analysisOptions;
+ //clone.declaredVariables = context.declaredVariables;
+ clone.sourceFactory = context.sourceFactory.clone();
+ // TODO(brianwilkerson) Check content cache. We either need to copy the
+ // cache into the clone or ensure that the context's cache is empty.
+
+ ChangeSet changeSet = new ChangeSet();
+ for (AnalysisTarget target in context.explicitTargets) {
+ if (target is Source) {
+ changeSet.addedSource(target);
+ }
+ }
+ clone.applyChanges(changeSet);
+ return clone;
+ }
+
+ /**
+ * Compare the results produced in the [original] context to those produced in
+ * the [clone].
+ */
+ void _compareContexts(
+ AnalysisContextImpl original, AnalysisContextImpl clone) {
+ AnalysisCache originalCache = original.analysisCache;
+ AnalysisCache cloneCache = clone.analysisCache;
+ List<AnalysisTarget> originalTargets = _getKeys(original, originalCache);
+ List<AnalysisTarget> cloneTargets = _getKeys(clone, cloneCache);
+
+ extraTargets =
+ new HashSet<AnalysisTarget>(equals: _equal, hashCode: _hashCode);
+ extraTargets.addAll(originalTargets);
+ extraTargets.removeAll(cloneTargets);
+
+ missingTargets =
+ new HashSet<AnalysisTarget>(equals: _equal, hashCode: _hashCode);
+ missingTargets.addAll(cloneTargets);
+ missingTargets.removeAll(originalTargets);
+
+ for (AnalysisTarget cloneTarget in cloneTargets) {
+ if (!missingTargets.contains(cloneTarget)) {
+ AnalysisTarget originalTarget = _find(originalTargets, cloneTarget);
+ CacheEntry originalEntry = originalCache.get(originalTarget);
+ CacheEntry cloneEntry = cloneCache.get(cloneTarget);
+ EntryComparison comparison =
+ new EntryComparison(cloneTarget, originalEntry, cloneEntry);
+ if (comparison.hasInterestingState()) {
+ targetMap[cloneTarget] = comparison;
+ }
+ }
+ }
+ }
+
+ /**
+ * Find the target in the list of [originalTargets] that is equal to the
+ * [cloneTarget].
+ */
+ AnalysisTarget _find(
+ List<AnalysisTarget> originalTargets, AnalysisTarget cloneTarget) {
+ for (AnalysisTarget originalTarget in originalTargets) {
+ if (_equal(originalTarget, cloneTarget)) {
+ return originalTarget;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Return a list of the analysis targets in the given [cache] that are owned
+ * by the given [context].
+ */
+ List<AnalysisTarget> _getKeys(
+ AnalysisContextImpl context, AnalysisCache cache) {
+ List<AnalysisTarget> targets = <AnalysisTarget>[];
+ MapIterator<AnalysisTarget, CacheEntry> iterator =
+ cache.iterator(context: context);
+ while (iterator.moveNext()) {
+ targets.add(iterator.key);
+ }
+ return targets;
+ }
+
+ /**
+ * Validate the given [context].
+ */
+ void _validate(AnalysisContextImpl context) {
+ AnalysisContextImpl clone = _clone(context);
+ _analyze(clone);
+ _compareContexts(context, clone);
+ }
+
+ /**
+ * Write the list of [targets] to the [buffer].
+ */
+ void _writeTargetList(StringBuffer buffer, List<AnalysisTarget> targets) {
+ // TODO(brianwilkerson) Sort the list of targets.
+ //targets.sort();
+ for (AnalysisTarget target in targets) {
+ buffer.write('<p>');
+ buffer.write(target);
+ buffer.write(' (');
+ buffer.write(target.runtimeType);
+ buffer.write(')');
+ buffer.write('</p>');
+ }
+ }
+
+ /**
+ * Return `true` if the [first] and [second] objects are equal.
+ */
+ static bool _equal(Object first, Object second) {
+ //
+ // Compare possible null values.
+ //
+ if (first == null) {
+ return second == null;
+ } else if (second == null) {
+ return false;
+ }
+ //
+ // Handle special cases.
+ //
+ if (first is ConstantEvaluationTarget_Annotation &&
+ second is ConstantEvaluationTarget_Annotation) {
+ return _equal(first.source, second.source) &&
+ _equal(first.librarySource, second.librarySource) &&
+ _equal(first.annotation, second.annotation);
+ } else if (first is AstNode && second is AstNode) {
+ return first.runtimeType == second.runtimeType &&
+ first.offset == second.offset &&
+ first.length == second.length;
+ }
+ //
+ // Handle the general case.
+ //
+ return first == second;
+ }
+
+ /**
+ * Return a hash code for the given [object].
+ */
+ static int _hashCode(Object object) {
+ //
+ // Handle special cases.
+ //
+ if (object is ConstantEvaluationTarget_Annotation) {
+ return object.source.hashCode;
+ } else if (object is AstNode) {
+ return object.offset;
+ }
+ //
+ // Handle the general case.
+ //
+ return object.hashCode;
+ }
+}
+
+class ValueComparison {
+ /**
+ * The result value from the original context.
+ */
+ final Object originalValue;
+
+ /**
+ * The result value from the cloned context.
+ */
+ final Object cloneValue;
+
+ /**
+ * A description of the difference between the original and clone values, or
+ * `null` if the values are equal.
+ */
+ String description = null;
+
+ /**
+ * Initialize a newly created value comparison to represents the difference,
+ * if any, between the [originalValue] and the [cloneValue].
+ */
+ ValueComparison(this.originalValue, this.cloneValue) {
+ _performComparison();
+ }
+
+ /**
+ * Return `true` if this object represents a difference between the original
+ * and cloned values.
+ */
+ bool hasInterestingState() => description != null;
+
+ /**
+ * Write an HTML formatted description of the validation results to the given
+ * [buffer].
+ */
+ void writeOn(StringBuffer buffer) {
+ buffer.write('<p>');
+ buffer.write(description);
+ buffer.write('</p>');
+ }
+
+ bool _compareAnalysisErrors(
+ AnalysisError expected, AnalysisError actual, StringBuffer buffer) {
+ if (actual.errorCode == expected.errorCode &&
+ actual.source == expected.source &&
+ actual.offset == expected.offset) {
+ return true;
+ }
+ if (buffer != null) {
+ void write(AnalysisError originalError) {
+ buffer.write('a ');
+ buffer.write(originalError.errorCode.uniqueName);
+ buffer.write(' in ');
+ buffer.write(originalError.source.fullName);
+ buffer.write(' at ');
+ buffer.write(originalError.offset);
+ }
+
+ buffer.write('Expected ');
+ write(expected);
+ buffer.write('; found ');
+ write(actual);
+ }
+ return false;
+ }
+
+ bool _compareAstNodes(AstNode expected, AstNode actual, StringBuffer buffer) {
+ if (AstComparator.equalNodes(actual, expected)) {
+ return true;
+ }
+ if (buffer != null) {
+ // TODO(brianwilkerson) Compute where the difference is rather than just
+ // whether there is a difference.
+ buffer.write('Different AST nodes');
+ }
+ return false;
+ }
+
+ bool _compareConstantEvaluationTargets(ConstantEvaluationTarget expected,
+ ConstantEvaluationTarget actual, StringBuffer buffer) {
+ if (actual is ConstantEvaluationTarget_Annotation) {
+ ConstantEvaluationTarget_Annotation expectedAnnotation = expected;
+ ConstantEvaluationTarget_Annotation actualAnnotation = actual;
+ if (actualAnnotation.source == expectedAnnotation.source &&
+ actualAnnotation.librarySource == expectedAnnotation.librarySource &&
+ actualAnnotation.annotation == expectedAnnotation.annotation) {
+ return true;
+ }
+ if (buffer != null) {
+ void write(ConstantEvaluationTarget_Annotation target) {
+ Annotation annotation = target.annotation;
+ buffer.write(annotation);
+ buffer.write(' at ');
+ buffer.write(annotation.offset);
+ buffer.write(' in ');
+ buffer.write(target.source);
+ buffer.write(' in ');
+ buffer.write(target.librarySource);
+ }
+
+ buffer.write('Expected ');
+ write(expectedAnnotation);
+ buffer.write('; found ');
+ write(actualAnnotation);
+ }
+ return false;
+ }
+ if (buffer != null) {
+ buffer.write('Unknown class of ConstantEvaluationTarget: ');
+ buffer.write(actual.runtimeType);
+ }
+ return false;
+ }
+
+ bool _compareDartScripts(
+ DartScript expected, DartScript actual, StringBuffer buffer) {
+ // TODO(brianwilkerson) Implement this.
+ return true;
+ }
+
+ bool _compareDocuments(
+ html.Document expected, html.Document actual, StringBuffer buffer) {
+ // TODO(brianwilkerson) Implement this.
+ return true;
+ }
+
+ bool _compareElements(Element expected, Element actual, StringBuffer buffer) {
+ ElementComparator comparator = new ElementComparator();
+ comparator.compareElements(expected, actual);
+ if (comparator.hasDifference) {
+ if (buffer != null) {
+ buffer.write(comparator.description);
+ }
+ return false;
+ }
+ return true;
+ }
+
+ bool _compareLibrarySpecificUnits(LibrarySpecificUnit expected,
+ LibrarySpecificUnit actual, StringBuffer buffer) {
+ if (actual.library.fullName == expected.library.fullName &&
+ actual.unit.fullName == expected.unit.fullName) {
+ return true;
+ }
+ if (buffer != null) {
+ buffer.write('Expected ');
+ buffer.write(expected);
+ buffer.write('; found ');
+ buffer.write(actual);
+ }
+ return false;
+ }
+
+ bool _compareLineInfos(
+ LineInfo expected, LineInfo actual, StringBuffer buffer) {
+ // TODO(brianwilkerson) Implement this.
+ return true;
+ }
+
+ bool _compareLists(List expected, List actual, StringBuffer buffer) {
+ int expectedLength = expected.length;
+ int actualLength = actual.length;
+ int left = 0;
+ while (left < expectedLength &&
+ left < actualLength &&
+ _compareObjects(expected[left], actual[left], null)) {
+ left++;
+ }
+ if (left == actualLength) {
+ if (left == expectedLength) {
+ // The lists are the same length and the elements are equal.
+ return true;
+ }
+ if (buffer != null) {
+ buffer.write('Expected a list of length ');
+ buffer.write(expectedLength);
+ buffer.write('; found a list of length ');
+ buffer.write(actualLength);
+ buffer.write(' that was a prefix of the expected list');
+ }
+ return false;
+ } else if (left == expectedLength) {
+ if (buffer != null) {
+ buffer.write('Expected a list of length ');
+ buffer.write(expectedLength);
+ buffer.write('; found a list of length ');
+ buffer.write(actualLength);
+ buffer.write(' that was an extension of the expected list');
+ }
+ return false;
+ }
+ int expectedRight = expectedLength - 1;
+ int actualRight = actualLength - 1;
+ while (expectedRight > left &&
+ actualRight > left &&
+ _compareObjects(expected[expectedRight], actual[actualRight], null)) {
+ actualRight--;
+ expectedRight--;
+ }
+ if (buffer != null) {
+ void write(int left, int right, int length) {
+ buffer.write('the elements (');
+ buffer.write(left);
+ buffer.write('..');
+ buffer.write(right);
+ buffer.write(') in a list of length ');
+ buffer.write(length);
+ }
+
+ buffer.write('Expected ');
+ write(left, expectedRight, expectedLength);
+ buffer.write(' to match ');
+ write(left, actualRight, actualLength);
+ buffer.write(' but they did not');
+ }
+ return false;
+ }
+
+ /**
+ * Return `true` if the [expected] and [actual] objects are equal. If they are
+ * not equal, and the given [buffer] is not `null`, then a description of the
+ * difference will be written to the [buffer].
+ */
+ bool _compareObjects(Object expected, Object actual, StringBuffer buffer) {
+ //
+ // Compare possible null values.
+ //
+ if (actual == null) {
+ if (expected == null) {
+ return true;
+ } else {
+ if (buffer != null) {
+ buffer.write('Expected an instance of ');
+ buffer.write(expected.runtimeType);
+ buffer.write('; found null');
+ }
+ return false;
+ }
+ }
+ Type actualType = actual.runtimeType;
+ if (expected == null) {
+ if (buffer != null) {
+ buffer.write('Expected null; found an instance of ');
+ buffer.write(actualType);
+ }
+ return false;
+ }
+ Type expectedType = expected.runtimeType;
+ //
+ // Compare the types.
+ //
+ if (expectedType != actualType) {
+ if (buffer != null) {
+ buffer.write('Expected an instance of ');
+ buffer.write(expectedType);
+ buffer.write('; found an instance of ');
+ buffer.write(actualType);
+ }
+ return false;
+ }
+ //
+ // Compare non-null values of the same type.
+ //
+ if (actual is bool) {
+ return _comparePrimitives(expected, actual, buffer);
+ } else if (actual is int) {
+ return _comparePrimitives(expected, actual, buffer);
+ } else if (actual is String) {
+ return _compareStrings(expected, actual, buffer);
+ } else if (actual is List) {
+ return _compareLists(expected, actual, buffer);
+ } else if (actual is AnalysisError) {
+ return _compareAnalysisErrors(expected, actual, buffer);
+ } else if (actual is AstNode) {
+ return _compareAstNodes(expected, actual, buffer);
+ } else if (actual is DartScript) {
+ return _compareDartScripts(expected, actual, buffer);
+ } else if (actual is html.Document) {
+ return _compareDocuments(expected, actual, buffer);
+ } else if (actual is Element) {
+ return _compareElements(expected, actual, buffer);
+ } else if (actual is LibrarySpecificUnit) {
+ return _compareLibrarySpecificUnits(expected, actual, buffer);
+ } else if (actual is LineInfo) {
+ return _compareLineInfos(expected, actual, buffer);
+ } else if (actual is ReferencedNames) {
+ return _compareReferencedNames(expected, actual, buffer);
+ } else if (actual is Source) {
+ return _compareSources(expected, actual, buffer);
+ } else if (actual is SourceKind) {
+ return _comparePrimitives(expected, actual, buffer);
+ } else if (actual is Token) {
+ return _compareTokenStreams(expected, actual, buffer);
+ } else if (actual is TypeProvider) {
+ return true;
+ } else if (actual is UsedLocalElements) {
+ return _compareUsedLocalElements(expected, actual, buffer);
+ } else if (actual is UsedImportedElements) {
+ return _compareUsedImportedElements(expected, actual, buffer);
+ } else if (actual is ConstantEvaluationTarget) {
+ return _compareConstantEvaluationTargets(expected, actual, buffer);
+ }
+ if (buffer != null) {
+ buffer.write('Cannot compare values of type ');
+ buffer.write(actualType);
+ }
+ return false;
+ }
+
+ bool _comparePrimitives(Object expected, Object actual, StringBuffer buffer) {
+ if (actual == expected) {
+ return true;
+ }
+ if (buffer != null) {
+ buffer.write('Expected ');
+ buffer.write(expected);
+ buffer.write('; found ');
+ buffer.write(actual);
+ }
+ return false;
+ }
+
+ bool _compareReferencedNames(
+ ReferencedNames expected, ReferencedNames actual, StringBuffer buffer) {
+ Set<String> expectedNames = expected.names;
+ Map<String, Set<String>> expectedUserToDependsOn = expected.userToDependsOn;
+ Set<String> expectedKeys = expectedUserToDependsOn.keys.toSet();
+
+ Set<String> actualNames = actual.names;
+ Map<String, Set<String>> actualUserToDependsOn = actual.userToDependsOn;
+ Set<String> actualKeys = actualUserToDependsOn.keys.toSet();
+
+ Set<String> missingNames = expectedNames.difference(actualNames);
+ Set<String> extraNames = actualNames.difference(expectedNames);
+ Set<String> missingKeys = expectedKeys.difference(actualKeys);
+ Set<String> extraKeys = actualKeys.difference(expectedKeys);
+ Map<String, List<Set<String>>> mismatchedDependencies =
+ new HashMap<String, List<Set<String>>>();
+ Set<String> commonKeys = expectedKeys.intersection(actualKeys);
+ for (String key in commonKeys) {
+ Set<String> expectedDependencies = expectedUserToDependsOn[key];
+ Set<String> actualDependencies = actualUserToDependsOn[key];
+ Set<String> missingDependencies =
+ expectedDependencies.difference(actualDependencies);
+ Set<String> extraDependencies =
+ actualDependencies.difference(expectedDependencies);
+ if (missingDependencies.isNotEmpty || extraDependencies.isNotEmpty) {
+ mismatchedDependencies[key] = [missingDependencies, extraDependencies];
+ }
+ }
+
+ if (missingNames.isEmpty &&
+ extraNames.isEmpty &&
+ missingKeys.isEmpty &&
+ extraKeys.isEmpty &&
+ mismatchedDependencies.isEmpty) {
+ return true;
+ }
+ if (buffer != null) {
+ void write(String title, Set<String> names) {
+ buffer.write(names.length);
+ buffer.write(' ');
+ buffer.write(title);
+ buffer.write(': {');
+ bool first = true;
+ for (String name in names) {
+ if (first) {
+ first = false;
+ } else {
+ buffer.write(', ');
+ }
+ buffer.write(name);
+ }
+ buffer.write('}');
+ }
+ bool needsNewline = false;
+ if (missingNames.isNotEmpty) {
+ buffer.write('Has ');
+ write('missing names', missingNames);
+ needsNewline = true;
+ }
+ if (extraNames.isNotEmpty) {
+ if (needsNewline) {
+ buffer.write('</p><p>');
+ }
+ buffer.write('Has ');
+ write('extra names', extraNames);
+ needsNewline = true;
+ }
+ if (missingKeys.isNotEmpty) {
+ if (needsNewline) {
+ buffer.write('</p><p>');
+ }
+ buffer.write('Has ');
+ write('missing keys', missingKeys);
+ needsNewline = true;
+ }
+ if (extraKeys.isNotEmpty) {
+ if (needsNewline) {
+ buffer.write('</p><p>');
+ }
+ buffer.write('Has ');
+ write('extra keys', extraKeys);
+ needsNewline = true;
+ }
+ mismatchedDependencies.forEach((String key, List<Set<String>> value) {
+ Set<String> missingDependencies = value[0];
+ Set<String> extraDependencies = value[1];
+ if (needsNewline) {
+ buffer.write('</p><p>');
+ }
+ buffer.write('The key ');
+ buffer.write(key);
+ buffer.write(' has ');
+ bool needsConjunction = false;
+ if (missingNames.isNotEmpty) {
+ write('missing dependencies', missingDependencies);
+ needsConjunction = true;
+ }
+ if (extraNames.isNotEmpty) {
+ if (needsConjunction) {
+ buffer.write(' and ');
+ }
+ write('extra dependencies', extraDependencies);
+ }
+ needsNewline = true;
+ });
+ }
+ return true;
+ }
+
+ bool _compareSources(Source expected, Source actual, StringBuffer buffer) {
+ if (actual.fullName == expected.fullName) {
+ return true;
+ }
+ if (buffer != null) {
+ buffer.write('Expected a source for ');
+ buffer.write(expected.fullName);
+ buffer.write('; found a source for ');
+ buffer.write(actual.fullName);
+ }
+ return false;
+ }
+
+ bool _compareStrings(String expected, String actual, StringBuffer buffer) {
+ if (actual == expected) {
+ return true;
+ }
+ int expectedLength = expected.length;
+ int actualLength = actual.length;
+ int left = 0;
+ while (left < actualLength &&
+ left < expectedLength &&
+ actual.codeUnitAt(left) == expected.codeUnitAt(left)) {
+ left++;
+ }
+ if (left == actualLength) {
+ if (buffer != null) {
+ buffer.write('Expected ...[');
+ buffer.write(expected.substring(left));
+ buffer.write(']; found ...[]');
+ }
+ return false;
+ } else if (left == expectedLength) {
+ if (buffer != null) {
+ buffer.write('Expected ...[]; found ...[');
+ buffer.write(actual.substring(left));
+ buffer.write(']');
+ }
+ return false;
+ }
+ int actualRight = actualLength - 1;
+ int expectedRight = expectedLength - 1;
+ while (actualRight > left &&
+ expectedRight > left &&
+ actual.codeUnitAt(actualRight) == expected.codeUnitAt(expectedRight)) {
+ actualRight--;
+ expectedRight--;
+ }
+ if (buffer != null) {
+ void write(String string, int left, int right) {
+ buffer.write('...[');
+ buffer.write(string.substring(left, right));
+ buffer.write(']... (');
+ buffer.write(left);
+ buffer.write('..');
+ buffer.write(right);
+ buffer.write(')');
+ }
+
+ buffer.write('Expected ');
+ write(expected, left, expectedRight);
+ buffer.write('; found ');
+ write(actual, left, actualRight);
+ }
+ return false;
+ }
+
+ bool _compareTokenStreams(Token expected, Token actual, StringBuffer buffer) {
+ bool equals(Token originalToken, Token cloneToken) {
+ return originalToken.type == cloneToken.type &&
+ originalToken.offset == cloneToken.offset &&
+ originalToken.lexeme == cloneToken.lexeme;
+ }
+
+ Token actualLeft = actual;
+ Token expectedLeft = expected;
+ while (actualLeft.type != TokenType.EOF &&
+ expectedLeft.type != TokenType.EOF &&
+ equals(actualLeft, expectedLeft)) {
+ actualLeft = actualLeft.next;
+ expectedLeft = expectedLeft.next;
+ }
+ if (actualLeft.type == TokenType.EOF &&
+ expectedLeft.type == TokenType.EOF) {
+ return true;
+ }
+ if (buffer != null) {
+ void write(Token token) {
+ buffer.write(token.type);
+ buffer.write(' at ');
+ buffer.write(token.offset);
+ buffer.write(' (');
+ buffer.write(token.lexeme);
+ buffer.write(')');
+ }
+
+ buffer.write('Expected ');
+ write(expectedLeft);
+ buffer.write('; found ');
+ write(actualLeft);
+ }
+ return false;
+ }
+
+ bool _compareUsedImportedElements(UsedImportedElements expected,
+ UsedImportedElements actual, StringBuffer buffer) {
+ // TODO(brianwilkerson) Implement this.
+ return true;
+ }
+
+ bool _compareUsedLocalElements(UsedLocalElements expected,
+ UsedLocalElements actual, StringBuffer buffer) {
+ // TODO(brianwilkerson) Implement this.
+ return true;
+ }
+
+ /**
+ * Determine whether or not there is any interesting difference between the
+ * original and cloned values.
+ */
+ void _performComparison() {
+ StringBuffer buffer = new StringBuffer();
+ if (!_compareObjects(cloneValue, originalValue, buffer)) {
+ description = buffer.toString();
+ }
+ }
+}
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 8049890..d96edc0 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -75,6 +75,10 @@
}
}
+ void processRequiredPlugins() {
+ AnalysisEngine.instance.processRequiredPlugins();
+ }
+
CompilationUnit resolveDartUnit(Source unitSource, Source librarySource) {
return context.resolveCompilationUnit2(unitSource, librarySource);
}
@@ -84,6 +88,7 @@
}
void setUp() {
+ processRequiredPlugins();
setupResourceProvider();
resourceResolver = new ResourceUriResolver(provider);
packageMap = new Map<String, List<Folder>>();
@@ -121,28 +126,12 @@
}
@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/notification_analysis_options_test.dart b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
index 966559b..a24b811 100644
--- a/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_analysis_options_test.dart
@@ -23,9 +23,6 @@
@reflectiveTest
class AnalysisOptionsFileNotificationTest extends AbstractAnalysisTest {
- /// Cached model state in case tests need to set task model to on/off.
- bool wasTaskModelEnabled;
-
Map<String, List<AnalysisError>> filesErrors = {};
final testSource = '''
@@ -78,13 +75,10 @@
void setUp() {
super.setUp();
server.handlers = [new AnalysisDomainHandler(server)];
- wasTaskModelEnabled = AnalysisEngine.instance.useTaskModel;
- AnalysisEngine.instance.useTaskModel = true;
}
@override
void tearDown() {
- AnalysisEngine.instance.useTaskModel = wasTaskModelEnabled;
filesErrors[optionsFilePath] = [];
filesErrors[testFile] = [];
super.tearDown();
@@ -108,10 +102,10 @@
await waitForTasksFinished();
// Verify options file.
- expect(optionsFileErrors, hasLength(0));
+ expect(optionsFileErrors, isEmpty);
// Verify test file.
- expect(testFileErrors, hasLength(0));
+ expect(testFileErrors, isEmpty);
}
test_error_filter_removed() async {
@@ -132,10 +126,10 @@
await waitForTasksFinished();
// Verify options file.
- expect(optionsFileErrors, hasLength(0));
+ expect(optionsFileErrors, isEmpty);
// Verify test file.
- expect(testFileErrors, hasLength(0));
+ expect(testFileErrors, isEmpty);
addOptionsFile('''
analyzer:
@@ -147,7 +141,7 @@
await waitForTasksFinished();
// Verify options file.
- expect(optionsFileErrors, hasLength(0));
+ expect(optionsFileErrors, isEmpty);
// Verify test file.
expect(testFileErrors, hasLength(1));
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index dbbe7af..02b05ec 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -25,9 +25,6 @@
class NotificationErrorsTest extends AbstractAnalysisTest {
Map<String, List<AnalysisError>> filesErrors = {};
- /// Cached model state in case tests need to set task model to on/off.
- bool wasTaskModelEnabled;
-
void processNotification(Notification notification) {
if (notification.event == ANALYSIS_ERRORS) {
var decoded = new AnalysisErrorsParams.fromNotification(notification);
@@ -39,13 +36,6 @@
void setUp() {
super.setUp();
server.handlers = [new AnalysisDomainHandler(server),];
- wasTaskModelEnabled = AnalysisEngine.instance.useTaskModel;
- }
-
- @override
- void tearDown() {
- AnalysisEngine.instance.useTaskModel = wasTaskModelEnabled;
- super.tearDown();
}
test_importError() async {
@@ -66,9 +56,6 @@
}
test_lintError() async {
- // Requires task model.
- AnalysisEngine.instance.useTaskModel = true;
-
var camelCaseTypesLintName = 'camel_case_types';
addFile(
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index 6fbc5d8..3e09632 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -107,11 +107,7 @@
server.updateContent('2', {testFile: new RemoveContentOverlay()});
// Validate that at the end the unit was indexed.
await server.onAnalysisComplete;
- if (AnalysisEngine.instance.useTaskModel) {
- verify(server.index.index(anyObject, testUnitMatcher)).times(3);
- } else {
- verify(server.index.index(anyObject, testUnitMatcher)).times(2);
- }
+ verify(server.index.index(anyObject, testUnitMatcher)).times(3);
}
test_multiple_contexts() async {
@@ -136,8 +132,9 @@
library baz;
f(int i) {}
''');
- Request request = new AnalysisSetAnalysisRootsParams(
- ['/project1', '/project2'], []).toRequest('0');
+ Request request =
+ new AnalysisSetAnalysisRootsParams(['/project1', '/project2'], [])
+ .toRequest('0');
handleSuccessfulRequest(request);
{
await server.onAnalysisComplete;
@@ -166,8 +163,9 @@
String filePath = '/User/project1/test.dart';
Folder folder1 = resourceProvider.newFolder('/User/project1');
Folder folder2 = resourceProvider.newFolder('/User/project2');
- Request request = new AnalysisSetAnalysisRootsParams(
- [folder1.path, folder2.path], []).toRequest('0');
+ Request request =
+ new AnalysisSetAnalysisRootsParams([folder1.path, folder2.path], [])
+ .toRequest('0');
handleSuccessfulRequest(request);
// exactly 2 contexts
expect(server.folderMap, hasLength(2));
@@ -274,6 +272,4 @@
}
}
-class _MockIndex extends TypedMock implements Index {
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
+class _MockIndex extends TypedMock implements Index {}
diff --git a/pkg/analysis_server/test/analysis_abstract.dart b/pkg/analysis_server/test/analysis_abstract.dart
index de27610..5c0616e 100644
--- a/pkg/analysis_server/test/analysis_abstract.dart
+++ b/pkg/analysis_server/test/analysis_abstract.dart
@@ -97,22 +97,27 @@
}
AnalysisServer createAnalysisServer(Index index) {
+ //
+ // Collect plugins
+ //
ServerPlugin serverPlugin = new ServerPlugin();
- // TODO(pq): this convoluted extension registry dance needs cleanup.
- List<Plugin> plugins = <Plugin>[
- serverPlugin,
- linterPlugin,
- linterServerPlugin,
- dartCompletionPlugin,
- ];
- // Accessing `taskManager` ensures that AE plugins are registered.
- AnalysisEngine.instance.taskManager;
- plugins.addAll(AnalysisEngine.instance.supportedPlugins);
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(serverPlugin);
+ plugins.add(dartCompletionPlugin);
+ plugins.add(linterPlugin);
+ plugins.add(linterServerPlugin);
addServerPlugins(plugins);
- // process plugins
+ //
+ // Process plugins
+ //
ExtensionManager manager = new ExtensionManager();
manager.processPlugins(plugins);
- // create server
+ //
+ // Create server
+ //
return new AnalysisServer(
serverChannel,
resourceProvider,
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 58179eb..e9a1663 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -21,6 +21,7 @@
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:plugin/manager.dart';
+import 'package:plugin/plugin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:typed_mock/typed_mock.dart';
import 'package:unittest/unittest.dart';
@@ -119,23 +120,31 @@
});
}
+ void processRequiredPlugins() {
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(server.serverPlugin);
+
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ }
+
void setUp() {
channel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
packageMapProvider = new MockPackageMapProvider();
- ExtensionManager manager = new ExtensionManager();
- ServerPlugin serverPlugin = new ServerPlugin();
- manager.processPlugins([serverPlugin]);
server = new AnalysisServer(
channel,
resourceProvider,
packageMapProvider,
null,
- serverPlugin,
+ new ServerPlugin(),
new AnalysisServerOptions(),
new MockSdk(),
InstrumentationService.NULL_SERVICE,
rethrowExceptions: true);
+ processRequiredPlugins();
}
Future test_contextDisposed() {
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index 0d5ea53..86defe8 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -1895,8 +1895,7 @@
main() {
B.!1;
}''',
- <String>["1+FIELD_B", "1-FIELD_A", "1+methodB", "1-methodA"],
- failingTests: '1');
+ <String>["1+FIELD_B", "1-FIELD_A", "1+methodB", "1-methodA"]);
buildTests(
'testCompletion_propertyAccess_whenInstanceTarget',
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 9f51368..082f28d 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -11,12 +11,18 @@
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/source/embedder.dart';
+import 'package:analyzer/source/error_processor.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/generated/source_io.dart';
+import 'package:analyzer/src/services/lint.dart';
+import 'package:linter/src/plugin/linter_plugin.dart';
+import 'package:linter/src/rules/avoid_as.dart';
import 'package:package_config/packages.dart';
import 'package:path/path.dart';
+import 'package:plugin/manager.dart';
+import 'package:plugin/plugin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -67,6 +73,37 @@
String projPath = '/my/proj';
+ AnalysisError missing_return =
+ new AnalysisError(new TestSource(), 0, 1, HintCode.MISSING_RETURN, [
+ ['x']
+ ]);
+
+ AnalysisError invalid_assignment_error =
+ new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
+ ['x'],
+ ['y']
+ ]);
+
+ AnalysisError unused_local_variable = new AnalysisError(
+ new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
+ ['x']
+ ]);
+
+ List<ErrorProcessor> get errorProcessors => callbacks.currentContext
+ .getConfigurationData(CONFIGURED_ERROR_PROCESSORS);
+
+ List<Linter> get lints => getLints(callbacks.currentContext);
+
+ AnalysisOptions get options => callbacks.currentContext.analysisOptions;
+
+ void deleteFile(List<String> pathComponents) {
+ String filePath = posix.joinAll(pathComponents);
+ resourceProvider.deleteFile(filePath);
+ }
+
+ ErrorProcessor getProcessor(AnalysisError error) =>
+ ErrorProcessor.getProcessor(callbacks.currentContext, error);
+
String newFile(List<String> pathComponents, [String content = '']) {
String filePath = posix.joinAll(pathComponents);
resourceProvider.newFile(filePath, content);
@@ -79,11 +116,22 @@
return folderPath;
}
+ void processRequiredPlugins() {
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(linterPlugin);
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ }
+
UriResolver providePackageResolver(Folder folder) {
return packageResolver;
}
void setUp() {
+ processRequiredPlugins();
resourceProvider = new MemoryResourceProvider();
packageMapProvider = new MockPackageMapProvider();
manager = new ContextManagerImpl(resourceProvider, providePackageResolver,
@@ -93,6 +141,99 @@
resourceProvider.newFolder(projPath);
}
+ test_analysis_options_file_delete() async {
+ // Setup .analysis_options
+ newFile(
+ [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
+ r'''
+embedder_libs:
+ "dart:foobar": "../sdk_ext/entry.dart"
+analyzer:
+ language:
+ enableGenericMethods: true
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Verify options were set.
+ expect(errorProcessors, hasLength(1));
+ expect(lints, hasLength(1));
+ expect(options.enableGenericMethods, isTrue);
+
+ // Remove options.
+ deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
+ await pumpEventQueue();
+
+ // Verify defaults restored.
+ expect(errorProcessors, isEmpty);
+ expect(lints, isEmpty);
+ expect(options.enableGenericMethods, isFalse);
+ }
+
+ test_analysis_options_file_delete_with_embedder() async {
+ // Setup _embedder.yaml.
+ String libPath = newFolder([projPath, LIB_NAME]);
+ newFile(
+ [libPath, '_embedder.yaml'],
+ r'''
+analyzer:
+ strong-mode: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
+''');
+
+ // Setup .packages file
+ newFile(
+ [projPath, '.packages'],
+ r'''
+test_pack:lib/''');
+
+ // Setup .analysis_options
+ newFile(
+ [projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE],
+ r'''
+analyzer:
+ language:
+ enableGenericMethods: true
+ errors:
+ unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
+''');
+
+ // Setup context.
+ manager.setRoots(<String>[projPath], <String>[], <String, String>{});
+ await pumpEventQueue();
+
+ // Verify options were set.
+ expect(options.enableGenericMethods, isTrue);
+ expect(options.strongMode, isTrue);
+ expect(errorProcessors, hasLength(2));
+ expect(lints, hasLength(2));
+
+ // Remove options.
+ deleteFile([projPath, AnalysisEngine.ANALYSIS_OPTIONS_FILE]);
+ await pumpEventQueue();
+
+ // Verify defaults restored.
+ expect(options.enableGenericMethods, isFalse);
+ expect(lints, hasLength(1));
+ expect(lints.first, new isInstanceOf<AvoidAs>());
+ expect(errorProcessors, hasLength(1));
+ expect(getProcessor(missing_return).severity, isNull);
+ }
+
test_analysis_options_parse_failure() async {
// Create files.
String libPath = newFolder([projPath, LIB_NAME]);
@@ -154,6 +295,11 @@
strong-mode: true
language:
enableSuperMixins: true
+ errors:
+ missing_return: false
+linter:
+ rules:
+ - avoid_as
''');
// Setup .packages file
newFile(
@@ -172,6 +318,9 @@
enableGenericMethods: true
errors:
unused_local_variable: false
+linter:
+ rules:
+ - camel_case_types
''');
// Setup context.
@@ -186,25 +335,31 @@
var context = contexts[0];
// Verify options.
- // * from `_embedder.yaml`:
+ // * from `_embedder.yaml`:
expect(context.analysisOptions.strongMode, isTrue);
expect(context.analysisOptions.enableSuperMixins, isTrue);
- // * from `.analysis_options`:
+ // * from `.analysis_options`:
expect(context.analysisOptions.enableGenericMethods, isTrue);
- // verify tests are excluded
+ // * verify tests are excluded
expect(callbacks.currentContextFilePaths[projPath].keys,
['/my/proj/sdk_ext/entry.dart']);
// Verify filter setup.
- List<ErrorFilter> filters =
- callbacks.currentContext.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- expect(filters, hasLength(1));
+ expect(errorProcessors, hasLength(2));
+
+ // * (embedder.)
+ expect(getProcessor(missing_return).severity, isNull);
+
+ // * (options.)
+ expect(getProcessor(unused_local_variable).severity, isNull);
+
+ // Verify lints.
+ var lintNames = lints.map((lint) => lint.name);
+
expect(
- filters.first(new AnalysisError(
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
- ['x']
- ])),
- isTrue);
+ lintNames,
+ unorderedEquals(
+ ['avoid_as' /* embedder */, 'camel_case_types' /* options */]));
// Sanity check embedder libs.
var source = context.sourceFactory.forUri('dart:foobar');
@@ -268,16 +423,8 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// Verify filter setup.
- List<ErrorFilter> filters =
- callbacks.currentContext.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- expect(filters, isNotNull);
- expect(filters, hasLength(1));
- expect(
- filters.first(new AnalysisError(
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
- ['x']
- ])),
- isTrue);
+ expect(errorProcessors, hasLength(1));
+ expect(getProcessor(unused_local_variable).severity, isNull);
}
test_error_filter_analysis_option_multiple_filters() async {
@@ -288,30 +435,16 @@
analyzer:
errors:
invalid_assignment: ignore
- unused_local_variable: ignore
+ unused_local_variable: error
''');
// Setup context.
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// Verify filter setup.
- List<ErrorFilter> filters =
- callbacks.currentContext.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- expect(filters, isNotNull);
- expect(filters, hasLength(2));
+ expect(errorProcessors, hasLength(2));
- var unused_error = new AnalysisError(
- new TestSource(), 0, 1, HintCode.UNUSED_LOCAL_VARIABLE, [
- ['x']
- ]);
-
- var invalid_assignment_error =
- new AnalysisError(new TestSource(), 0, 1, HintCode.INVALID_ASSIGNMENT, [
- ['x'],
- ['y']
- ]);
-
- expect(filters.any((filter) => filter(unused_error)), isTrue);
- expect(filters.any((filter) => filter(invalid_assignment_error)), isTrue);
+ expect(getProcessor(invalid_assignment_error).severity, isNull);
+ expect(getProcessor(unused_local_variable).severity, ErrorSeverity.ERROR);
}
test_error_filter_analysis_option_synonyms() async {
@@ -328,10 +461,8 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// Verify filter setup.
- List<ErrorFilter> filters =
- callbacks.currentContext.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- expect(filters, isNotNull);
- expect(filters, hasLength(2));
+ expect(errorProcessors, isNotNull);
+ expect(errorProcessors, hasLength(2));
}
test_error_filter_analysis_option_unpsecified() async {
@@ -347,9 +478,7 @@
manager.setRoots(<String>[projPath], <String>[], <String, String>{});
// Verify filter setup.
- List<ErrorFilter> filters =
- callbacks.currentContext.getConfigurationData(CONFIGURED_ERROR_FILTERS);
- expect(filters, isEmpty);
+ expect(errorProcessors, isEmpty);
}
test_ignoreFilesInPackagesFolder() {
diff --git a/pkg/analysis_server/test/domain_analysis_test.dart b/pkg/analysis_server/test/domain_analysis_test.dart
index 2c6fc7b..b7f4b34 100644
--- a/pkg/analysis_server/test/domain_analysis_test.dart
+++ b/pkg/analysis_server/test/domain_analysis_test.dart
@@ -119,6 +119,22 @@
expect(serverRef.getResolvedCompilationUnits(fileB), isEmpty);
});
});
+
+ test('not absolute', () async {
+ var response = testSetAnalysisRoots([], ['foo/bar']);
+ expect(
+ response,
+ isResponseFailure(
+ '0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
+ });
+
+ test('not normalized', () async {
+ var response = testSetAnalysisRoots([], ['/foo/../bar']);
+ expect(
+ response,
+ isResponseFailure(
+ '0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
+ });
});
group('included', () {
@@ -147,6 +163,22 @@
await server.onAnalysisComplete;
expect(serverRef.getResolvedCompilationUnits(fileB), hasLength(1));
});
+
+ test('not absolute', () async {
+ var response = testSetAnalysisRoots(['foo/bar'], []);
+ expect(
+ response,
+ isResponseFailure(
+ '0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
+ });
+
+ test('not normalized', () async {
+ var response = testSetAnalysisRoots(['/foo/../bar'], []);
+ expect(
+ response,
+ isResponseFailure(
+ '0', RequestErrorCode.INVALID_FILE_PATH_FORMAT));
+ });
});
});
@@ -167,8 +199,9 @@
resourceProvider.newFile('/p2/b.dart', 'library b;');
resourceProvider.newFile('/p2/c.dart', 'library c;');
- var setRootsRequest = new AnalysisSetAnalysisRootsParams(
- ['/p1', '/p2'], []).toRequest('0');
+ var setRootsRequest =
+ new AnalysisSetAnalysisRootsParams(['/p1', '/p2'], [])
+ .toRequest('0');
var setRootsResponse = handler.handleRequest(setRootsRequest);
expect(setRootsResponse, isResponseSuccess('0'));
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 888b7cc..619136b 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -29,6 +29,7 @@
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:plugin/manager.dart';
+import 'package:plugin/plugin.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
import 'package:unittest/unittest.dart';
@@ -52,13 +53,23 @@
int requestCount = 0;
String testFile2 = '/project/bin/test2.dart';
- /// Cached model state in case tests need to set task model to on/off.
- bool wasTaskModelEnabled;
-
AnalysisServer createAnalysisServer(Index index) {
- ExtensionManager manager = new ExtensionManager();
+ //
+ // Collect plugins
+ //
ServerPlugin serverPlugin = new ServerPlugin();
- manager.processPlugins([serverPlugin]);
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(serverPlugin);
+ addServerPlugins(plugins);
+ //
+ // Process plugins
+ //
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ //
+ // Create the server
+ //
return new Test_AnalysisServer(
super.serverChannel,
super.resourceProvider,
@@ -85,8 +96,6 @@
@override
void setUp() {
super.setUp();
- wasTaskModelEnabled = AnalysisEngine.instance.useTaskModel;
- AnalysisEngine.instance.useTaskModel = true;
createProject();
analysisDomain = handler;
completionDomain = new Test_CompletionDomainHandler(server);
@@ -99,7 +108,6 @@
super.tearDown();
analysisDomain = null;
completionDomain = null;
- AnalysisEngine.instance.useTaskModel = wasTaskModelEnabled;
}
/**
@@ -464,12 +472,25 @@
expect(replacementOffset, equals(completionOffset));
expect(replacementLength, equals(0));
assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
- assertHasResult(CompletionSuggestionKind.INVOCATION, 'foo');
+ assertHasResult(CompletionSuggestionKind.IDENTIFIER, 'foo');
assertNoResult('HtmlElement');
assertNoResult('test');
});
}
+ test_imports_prefixed2() {
+ addTestFile('''
+ import 'dart:html' as foo;
+ main() {foo.^}
+ ''');
+ return getSuggestions().then((_) {
+ expect(replacementOffset, equals(completionOffset));
+ expect(replacementLength, equals(0));
+ assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
+ assertNoResult('test');
+ });
+ }
+
test_invocation() {
addTestFile('class A {b() {}} main() {A a; a.^}');
return getSuggestions().then((_) {
@@ -632,6 +653,16 @@
});
}
+ test_static() {
+ addTestFile('class A {static b() {} c() {}} main() {A.^}');
+ return getSuggestions().then((_) {
+ expect(replacementOffset, equals(completionOffset));
+ expect(replacementLength, equals(0));
+ assertHasResult(CompletionSuggestionKind.INVOCATION, 'b');
+ assertNoResult('c');
+ });
+ }
+
test_topLevel() {
addTestFile('''
typedef foo();
diff --git a/pkg/analysis_server/test/domain_diagnostic_test.dart b/pkg/analysis_server/test/domain_diagnostic_test.dart
index 444e6cf..f234463 100644
--- a/pkg/analysis_server/test/domain_diagnostic_test.dart
+++ b/pkg/analysis_server/test/domain_diagnostic_test.dart
@@ -10,7 +10,9 @@
import 'package:analysis_server/src/plugin/server_plugin.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:plugin/manager.dart';
+import 'package:plugin/plugin.dart';
import 'package:unittest/unittest.dart';
import 'mock_sdk.dart';
@@ -25,11 +27,25 @@
initializeTestEnvironment();
setUp(() {
+ //
+ // Collect plugins
+ //
+ ServerPlugin serverPlugin = new ServerPlugin();
+ List<Plugin> plugins = <Plugin>[];
+ plugins.addAll(AnalysisEngine.instance.requiredPlugins);
+ plugins.add(AnalysisEngine.instance.commandLinePlugin);
+ plugins.add(AnalysisEngine.instance.optionsPlugin);
+ plugins.add(serverPlugin);
+ //
+ // Process plugins
+ //
+ ExtensionManager manager = new ExtensionManager();
+ manager.processPlugins(plugins);
+ //
+ // Create the server
+ //
var serverChannel = new MockServerChannel();
resourceProvider = new MemoryResourceProvider();
- ExtensionManager manager = new ExtensionManager();
- ServerPlugin serverPlugin = new ServerPlugin();
- manager.processPlugins([serverPlugin]);
server = new AnalysisServer(
serverChannel,
resourceProvider,
@@ -42,10 +58,6 @@
handler = new DiagnosticDomainHandler(server);
});
- tearDown(() {
- handler.sampler?.stop();
- });
-
group('DiagnosticDomainHandler', () {
test('getDiagnostics', () async {
String file = '/project/bin/test.dart';
@@ -68,7 +80,6 @@
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/sort_members_test.dart b/pkg/analysis_server/test/edit/sort_members_test.dart
index 8bae43f..a955360 100644
--- a/pkg/analysis_server/test/edit/sort_members_test.dart
+++ b/pkg/analysis_server/test/edit/sort_members_test.dart
@@ -34,8 +34,7 @@
handler = new EditDomainHandler(server);
}
- Future test_BAD_doesNotExist() async {
- await waitForTasksFinished();
+ test_BAD_doesNotExist() async {
Request request =
new EditSortMembersParams('/no/such/file.dart').toRequest('0');
Response response = handler.handleRequest(request);
@@ -43,21 +42,19 @@
isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
}
- Future test_BAD_hasParseError() async {
+ test_BAD_hasParseError() async {
addTestFile('''
main() {
print()
}
''');
- await waitForTasksFinished();
Request request = new EditSortMembersParams(testFile).toRequest('0');
Response response = handler.handleRequest(request);
expect(response,
isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_PARSE_ERRORS));
}
- Future test_BAD_notDartFile() async {
- await waitForTasksFinished();
+ test_BAD_notDartFile() async {
Request request =
new EditSortMembersParams('/not-a-Dart-file.txt').toRequest('0');
Response response = handler.handleRequest(request);
@@ -65,7 +62,21 @@
isResponseFailure('0', RequestErrorCode.SORT_MEMBERS_INVALID_FILE));
}
- Future test_OK_classMembers_method() {
+ test_OK_afterWaitForAnalysis() async {
+ addTestFile('''
+class C {}
+class A {}
+class B {}
+''');
+ await waitForTasksFinished();
+ return _assertSorted(r'''
+class A {}
+class B {}
+class C {}
+''');
+ }
+
+ test_OK_classMembers_method() async {
addTestFile('''
class A {
c() {}
@@ -82,7 +93,7 @@
''');
}
- Future test_OK_directives() {
+ test_OK_directives() async {
addTestFile('''
library lib;
@@ -133,7 +144,7 @@
''');
}
- Future test_OK_unitMembers_class() {
+ test_OK_unitMembers_class() async {
addTestFile('''
class C {}
class A {}
@@ -147,7 +158,6 @@
}
Future _assertSorted(String expectedCode) async {
- await waitForTasksFinished();
_requestSort();
String resultCode = SourceEdit.applySequence(testCode, fileEdit.edits);
expect(resultCode, expectedCode);
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index 5004f86..f4dcfeb 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -11,7 +11,6 @@
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analysis_server/src/constants.dart';
-import 'package:analysis_server/src/server/driver.dart' as analysisServer;
import 'package:path/path.dart';
import 'package:unittest/unittest.dart';
@@ -597,7 +596,6 @@
{bool debugServer: false,
int diagnosticPort,
bool profileServer: false,
- bool newTaskModel: true,
bool useAnalysisHighlight2: false}) {
if (_process != null) {
throw new Exception('Process already started');
@@ -627,9 +625,6 @@
if (useAnalysisHighlight2) {
arguments.add('--useAnalysisHighlight2');
}
- if (!newTaskModel) {
- arguments.add('--${analysisServer.Driver.DISABLE_NEW_TASK_MODEL}');
- }
// print('Launching $serverPath');
// print('$dartBinary ${arguments.join(' ')}');
return Process.start(dartBinary, arguments).then((Process process) {
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 2a0cd06..6266cb9 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -1307,7 +1307,6 @@
* "explicitFileCount": int
* "implicitFileCount": int
* "workItemQueueLength": int
- * "workItemQueueLengthAverage": String
* "cacheEntryExceptions": List<String>
* }
*/
@@ -1317,7 +1316,6 @@
"explicitFileCount": isInt,
"implicitFileCount": isInt,
"workItemQueueLength": isInt,
- "workItemQueueLengthAverage": isString,
"cacheEntryExceptions": isListOf(isString)
}));
@@ -2104,6 +2102,7 @@
* GET_REACHABLE_SOURCES_INVALID_FILE
* INVALID_ANALYSIS_ROOT
* INVALID_EXECUTION_CONTEXT
+ * INVALID_FILE_PATH_FORMAT
* INVALID_OVERLAY_CHANGE
* INVALID_PARAMETER
* INVALID_REQUEST
@@ -2130,6 +2129,7 @@
"GET_REACHABLE_SOURCES_INVALID_FILE",
"INVALID_ANALYSIS_ROOT",
"INVALID_EXECUTION_CONTEXT",
+ "INVALID_FILE_PATH_FORMAT",
"INVALID_OVERLAY_CHANGE",
"INVALID_PARAMETER",
"INVALID_REQUEST",
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 99be8fc..5aaec99 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -6,7 +6,7 @@
import 'package:analyzer/file_system/file_system.dart' as resource;
import 'package:analyzer/file_system/memory_file_system.dart' as resource;
-import 'package:analyzer/src/context/context.dart' as newContext;
+import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -219,11 +219,7 @@
@override
AnalysisContext get context {
if (_analysisContext == null) {
- if (AnalysisEngine.instance.useTaskModel) {
- _analysisContext = new newContext.SdkAnalysisContext();
- } else {
- _analysisContext = new SdkAnalysisContext();
- }
+ _analysisContext = new SdkAnalysisContext();
SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
_analysisContext.sourceFactory = factory;
ChangeSet changeSet = new ChangeSet();
diff --git a/pkg/analysis_server/test/mocks.dart b/pkg/analysis_server/test/mocks.dart
index 428f53b..efc19fd 100644
--- a/pkg/analysis_server/test/mocks.dart
+++ b/pkg/analysis_server/test/mocks.dart
@@ -72,23 +72,19 @@
class MockAnalysisContext extends StringTypedMock implements AnalysisContext {
MockAnalysisContext(String name) : super(name);
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockClassElement extends TypedMock implements ClassElement {
final ElementKind kind = ElementKind.CLASS;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockCompilationUnitElement extends TypedMock
implements CompilationUnitElement {
final ElementKind kind = ElementKind.COMPILATION_UNIT;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockConstructorElement extends TypedMock implements ConstructorElement {
final kind = ElementKind.CONSTRUCTOR;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockElement extends StringTypedMock implements Element {
@@ -99,55 +95,39 @@
@override
String get name => _toString;
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockFieldElement extends TypedMock implements FieldElement {
final ElementKind kind = ElementKind.FIELD;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockFunctionElement extends TypedMock implements FunctionElement {
final ElementKind kind = ElementKind.FUNCTION;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockFunctionTypeAliasElement extends TypedMock
implements FunctionTypeAliasElement {
final ElementKind kind = ElementKind.FUNCTION_TYPE_ALIAS;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
-class MockHtmlElement extends TypedMock implements HtmlElement {
- final ElementKind kind = ElementKind.HTML;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockImportElement extends TypedMock implements ImportElement {
final ElementKind kind = ElementKind.IMPORT;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockLibraryElement extends TypedMock implements LibraryElement {
final ElementKind kind = ElementKind.LIBRARY;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockLocalVariableElement extends TypedMock
implements LocalVariableElement {
final ElementKind kind = ElementKind.LOCAL_VARIABLE;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
-class MockLogger extends TypedMock implements Logger {
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
+class MockLogger extends TypedMock implements Logger {}
class MockMethodElement extends StringTypedMock implements MethodElement {
final kind = ElementKind.METHOD;
MockMethodElement([String name = 'method']) : super(name);
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/**
@@ -192,14 +172,12 @@
class MockParameterElement extends TypedMock implements ParameterElement {
final ElementKind kind = ElementKind.PARAMETER;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockPropertyAccessorElement extends TypedMock
implements PropertyAccessorElement {
final ElementKind kind;
MockPropertyAccessorElement(this.kind);
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
/**
@@ -255,7 +233,7 @@
if (_closed) {
throw new Exception('sendRequest after connection closed');
}
- // Wrap send request in future to simulate websocket
+ // Wrap send request in future to simulate WebSocket.
new Future(() => requestController.add(request));
return waitForResponse(request);
}
@@ -267,7 +245,7 @@
return;
}
responsesReceived.add(response);
- // Wrap send response in future to simulate websocket
+ // Wrap send response in future to simulate WebSocket.
new Future(() => responseController.add(response));
}
@@ -342,19 +320,16 @@
class MockSource extends StringTypedMock implements Source {
MockSource([String name = 'mocked.dart']) : super(name);
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockTopLevelVariableElement extends TypedMock
implements TopLevelVariableElement {
final ElementKind kind = ElementKind.TOP_LEVEL_VARIABLE;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class MockTypeParameterElement extends TypedMock
implements TypeParameterElement {
final ElementKind kind = ElementKind.TYPE_PARAMETER;
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class NoResponseException implements Exception {
diff --git a/pkg/analysis_server/test/operation/operation_queue_test.dart b/pkg/analysis_server/test/operation/operation_queue_test.dart
index ed7fbca..e6926c9 100644
--- a/pkg/analysis_server/test/operation/operation_queue_test.dart
+++ b/pkg/analysis_server/test/operation/operation_queue_test.dart
@@ -36,8 +36,6 @@
class AnalysisContextMock extends TypedMock implements InternalAnalysisContext {
List<Source> prioritySources = <Source>[];
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class AnalysisServerMock extends TypedMock implements AnalysisServer {
@@ -48,13 +46,9 @@
final SearchEngine searchEngine;
AnalysisServerMock({this.resourceProvider, this.searchEngine});
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
-class ServerContextManagerMock extends TypedMock implements ContextManager {
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
+class ServerContextManagerMock extends TypedMock implements ContextManager {}
@reflectiveTest
class ServerOperationQueueTest {
@@ -230,21 +224,15 @@
ServerOperationPriority get priority {
return ServerOperationPriority.ANALYSIS_NOTIFICATION;
}
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class _ServerOperationMock extends TypedMock implements ServerOperation {
final AnalysisContext context;
_ServerOperationMock([this.context]);
-
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
-class _SourceMock extends TypedMock implements Source {
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
+class _SourceMock extends TypedMock implements Source {}
class _SourceSensitiveOperationMock extends TypedMock
implements SourceSensitiveOperation {
@@ -257,8 +245,6 @@
return ServerOperationPriority.ANALYSIS_NOTIFICATION;
}
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-
@override
bool shouldBeDiscardedOnSourceChange(Source source) {
return source == this.source;
diff --git a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
index 592b8dd..a92c943 100644
--- a/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
+++ b/pkg/analysis_server/test/plugin/set_analysis_domain_test.dart
@@ -25,9 +25,7 @@
main() {
initializeTestEnvironment();
- if (AnalysisEngine.instance.useTaskModel) {
- defineReflectiveTests(SetAnalysisDomainTest);
- }
+ defineReflectiveTests(SetAnalysisDomainTest);
}
/**
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 5f503b6..a210a94 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -26,9 +26,7 @@
defineReflectiveTests(EnumTest);
}
-class AnalysisErrorMock extends TypedMock implements engine.AnalysisError {
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
+class AnalysisErrorMock extends TypedMock implements engine.AnalysisError {}
@reflectiveTest
class AnalysisErrorTest {
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 63180b7..7812fd8 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -16,7 +16,6 @@
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';
-import 'package:analysis_server/src/services/completion/prefixed_element_contributor.dart';
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';
@@ -356,29 +355,6 @@
return cs;
}
- CompletionSuggestion assertSuggestNamedConstructor(
- String name, String returnType,
- [int relevance = DART_RELEVANCE_DEFAULT,
- CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
- if (contributor is PrefixedElementContributor) {
- CompletionSuggestion cs =
- assertSuggest(name, csKind: kind, relevance: relevance);
- protocol.Element element = cs.element;
- expect(element, isNotNull);
- expect(element.kind, equals(protocol.ElementKind.CONSTRUCTOR));
- expect(element.name, equals(name));
- String param = element.parameters;
- expect(param, isNotNull);
- expect(param[0], equals('('));
- expect(param[param.length - 1], equals(')'));
- expect(element.returnType, equals(returnType));
- assertHasParameterInfo(cs);
- return cs;
- } else {
- return assertNotSuggested(name);
- }
- }
-
CompletionSuggestion assertSuggestParameter(String name, String returnType,
{int relevance: DART_RELEVANCE_PARAMETER}) {
return assertNotSuggested(name);
@@ -660,11 +636,7 @@
CompletionSuggestion assertSuggestInvocationClass(String name,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (contributor is PrefixedElementContributor) {
- return assertSuggestClass(name, relevance: relevance);
- } else {
- return assertNotSuggested(name);
- }
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestInvocationField(String name, String type,
@@ -675,42 +647,24 @@
CompletionSuggestion assertSuggestInvocationGetter(
String name, String returnType,
{int relevance: DART_RELEVANCE_DEFAULT, bool isDeprecated: false}) {
- if (contributor is PrefixedElementContributor) {
- return assertSuggestGetter(name, returnType,
- relevance: relevance, isDeprecated: isDeprecated);
- } else {
- return assertNotSuggested(name);
- }
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestInvocationMethod(
String name, String declaringType, String returnType,
{int relevance: DART_RELEVANCE_DEFAULT}) {
- if (contributor is PrefixedElementContributor) {
- return assertSuggestMethod(name, declaringType, returnType,
- relevance: relevance);
- } else {
- return assertNotSuggested(name);
- }
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestInvocationSetter(String name,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (contributor is PrefixedElementContributor) {
- return assertSuggestSetter(name);
- } else {
- return assertNotSuggested(name);
- }
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestInvocationTopLevelVar(
String name, String returnType,
[int relevance = DART_RELEVANCE_DEFAULT]) {
- if (contributor is PrefixedElementContributor) {
- return assertSuggestTopLevelVar(name, returnType, relevance);
- } else {
- return assertNotSuggested(name);
- }
+ return assertNotSuggested(name);
}
CompletionSuggestion assertSuggestLocalClass(String name,
@@ -1336,7 +1290,8 @@
assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
//assertSuggestImportedClass('F', COMPLETION_RELEVANCE_LOW);
- assertSuggestLibraryPrefix('g');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('g');
assertNotSuggested('G');
//assertSuggestImportedClass('H', COMPLETION_RELEVANCE_LOW);
assertSuggestImportedClass('Object');
@@ -1447,7 +1402,8 @@
assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
//assertSuggestImportedClass('F', COMPLETION_RELEVANCE_LOW);
- assertSuggestLibraryPrefix('g');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('g');
assertNotSuggested('G');
//assertSuggestImportedClass('H', COMPLETION_RELEVANCE_LOW);
assertSuggestImportedClass('Object');
@@ -1570,7 +1526,8 @@
assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
//assertSuggestImportedClass('F', COMPLETION_RELEVANCE_LOW);
- assertSuggestLibraryPrefix('g');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('g');
assertNotSuggested('G');
//assertSuggestImportedClass('H', COMPLETION_RELEVANCE_LOW);
assertSuggestImportedClass('Object');
@@ -1677,7 +1634,8 @@
assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
//assertSuggestImportedClass('F', COMPLETION_RELEVANCE_LOW);
- assertSuggestLibraryPrefix('g');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('g');
assertNotSuggested('G');
//assertSuggestImportedClass('H', COMPLETION_RELEVANCE_LOW);
assertSuggestImportedClass('Object');
@@ -2124,7 +2082,8 @@
expect(suggestionO.element.isPrivate, isFalse);
}
assertNotSuggested('T');
- assertSuggestLibraryPrefix('x');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('x');
});
}
@@ -2147,7 +2106,8 @@
assertSuggestLocalClass('_B');
assertSuggestImportedClass('Object');
assertNotSuggested('T');
- assertSuggestLibraryPrefix('x');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('x');
});
}
@@ -2170,7 +2130,8 @@
assertSuggestLocalClass('_B');
assertSuggestImportedClass('String');
assertNotSuggested('T');
- assertSuggestLibraryPrefix('x');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('x');
});
}
@@ -2193,7 +2154,8 @@
assertSuggestLocalClass('_B');
assertSuggestImportedClass('String');
assertNotSuggested('Sew');
- assertSuggestLibraryPrefix('Soo');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('Soo');
});
}
@@ -2216,7 +2178,8 @@
assertSuggestLocalClass('_B');
assertSuggestImportedClass('Object');
assertNotSuggested('T');
- assertSuggestLibraryPrefix('x');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('x');
});
}
@@ -2239,7 +2202,8 @@
assertSuggestLocalClass('_B');
assertSuggestImportedClass('Object');
assertNotSuggested('T');
- assertSuggestLibraryPrefix('x');
+ // Suggested by LibraryPrefixContributor
+ assertNotSuggested('x');
});
}
@@ -2452,7 +2416,8 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestNamedConstructor('c', 'X');
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
assertNotSuggested('F1');
assertNotSuggested('T1');
assertNotSuggested('_d');
@@ -2479,7 +2444,8 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestNamedConstructor('c', 'X');
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
assertNotSuggested('F1');
assertNotSuggested('T1');
assertNotSuggested('_d');
@@ -2497,7 +2463,8 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset - 2);
expect(request.replacementLength, 13);
- assertSuggestNamedConstructor('fromCharCodes', 'String');
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('fromCharCodes');
assertNotSuggested('isEmpty');
assertNotSuggested('isNotEmpty');
assertNotSuggested('length');
@@ -2518,8 +2485,9 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestNamedConstructor('c', 'X');
- assertSuggestNamedConstructor('_d', 'X');
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('_d');
assertNotSuggested('F1');
assertNotSuggested('T1');
assertNotSuggested('z');
@@ -2539,8 +2507,9 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestNamedConstructor('c', 'X');
- assertSuggestNamedConstructor('_d', 'X');
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('_d');
assertNotSuggested('F1');
assertNotSuggested('T1');
assertNotSuggested('z');
@@ -3878,9 +3847,10 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestInvocationField('scA', 'String');
- assertSuggestInvocationField('scB', 'int');
- assertSuggestInvocationField('scI', null);
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('scA');
+ assertNotSuggested('scB');
+ assertNotSuggested('scI');
assertNotSuggested('b');
assertNotSuggested('_c');
assertNotSuggested('d');
@@ -4002,9 +3972,10 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestInvocationClass('X');
- assertSuggestInvocationClass('Y');
- assertSuggestInvocationTopLevelVar('T1', null);
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('X');
+ assertNotSuggested('Y');
+ assertNotSuggested('T1');
assertNotSuggested('T2');
assertNotSuggested('Object');
assertNotSuggested('b');
@@ -4031,8 +4002,9 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestInvocationClass('X');
- assertSuggestInvocationClass('Y');
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('X');
+ assertNotSuggested('Y');
assertNotSuggested('T1');
assertNotSuggested('T2');
assertNotSuggested('Object');
@@ -4060,8 +4032,9 @@
return computeFull((bool result) {
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
- assertSuggestInvocationClass('X');
- assertSuggestInvocationClass('Y');
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('X');
+ assertNotSuggested('Y');
assertNotSuggested('T1');
assertNotSuggested('T2');
assertNotSuggested('Object');
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index 273509c..0a14ef1 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -31,15 +31,19 @@
void assertSuggestArgumentList(
List<String> paramNames, List<String> paramTypes) {
- CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
- CompletionSuggestion cs = getSuggest(csKind: csKind);
- if (cs == null) {
- failedCompletion('expected completion $csKind', suggestions);
- }
- assertSuggestArgumentList_params(
- paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
- expect(cs.relevance, DART_RELEVANCE_HIGH);
- assertNoOtherSuggestions([cs]);
+ // DEPRECATED... argument lists are no longer suggested.
+ // See https://github.com/dart-lang/sdk/issues/25197
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+
+ // CompletionSuggestionKind csKind = CompletionSuggestionKind.ARGUMENT_LIST;
+ // CompletionSuggestion cs = getSuggest(csKind: csKind);
+ // if (cs == null) {
+ // failedCompletion('expected completion $csKind', suggestions);
+ // }
+ // assertSuggestArgumentList_params(
+ // paramNames, paramTypes, cs.parameterNames, cs.parameterTypes);
+ // expect(cs.relevance, DART_RELEVANCE_HIGH);
+ // assertNoOtherSuggestions([cs]);
}
void assertSuggestArgumentList_params(
@@ -302,6 +306,27 @@
assertNoSuggestions();
}
+ test_ArgumentList_imported_function_named_param_label1() async {
+ //
+ addTestSource('main() { int.parse("16", r^: 16);}');
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ }
+
+ test_ArgumentList_imported_function_named_param_label2() async {
+ //
+ addTestSource('main() { int.parse("16", ^r: 16);}');
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ }
+
+ test_ArgumentList_imported_function_named_param_label3() async {
+ //
+ addTestSource('main() { int.parse("16", ^: 16);}');
+ await computeSuggestions();
+ assertSuggestArguments(namedArguments: ['radix', 'onError']);
+ }
+
test_ArgumentList_local_constructor_named_param() async {
//
addTestSource('''
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
index d75024b..59e5e69 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -368,6 +368,9 @@
if (libraries.isNotEmpty) {
return new Future.value(libraries);
}
+ if (times == 0) {
+ fail('failed to determine libraries containing $testSource');
+ }
context.performAnalysisTask();
// We use a delayed future to allow microtask events to finish. The
// Future.value or Future() constructors use scheduleMicrotask themselves and
@@ -380,23 +383,33 @@
Future computeSuggestions([int times = 200]) async {
CompletionRequestImpl baseRequest = new CompletionRequestImpl(
context, provider, searchEngine, testSource, completionOffset);
- request = new DartCompletionRequestImpl.forRequest(baseRequest);
+
+ // Build the request
+ Completer<DartCompletionRequest> requestCompleter =
+ new Completer<DartCompletionRequest>();
+ DartCompletionRequestImpl
+ .from(baseRequest)
+ .then((DartCompletionRequest request) {
+ requestCompleter.complete(request);
+ });
+ request = await performAnalysis(times, requestCompleter);
+
var range = new ReplacementRange.compute(request.offset, request.target);
replacementOffset = range.offset;
replacementLength = range.length;
- Completer<List<CompletionSuggestion>> completer =
+ Completer<List<CompletionSuggestion>> suggestionCompleter =
new Completer<List<CompletionSuggestion>>();
// Request completions
contributor
.computeSuggestions(request)
.then((List<CompletionSuggestion> computedSuggestions) {
- completer.complete(computedSuggestions);
+ suggestionCompleter.complete(computedSuggestions);
});
// Perform analysis until the suggestions have been computed
// or the max analysis cycles ([times]) has been reached
- suggestions = await performAnalysis(times, completer);
+ suggestions = await performAnalysis(times, suggestionCompleter);
expect(suggestions, isNotNull, reason: 'expected suggestions');
}
diff --git a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
index 8933b0a..1d3549d 100644
--- a/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/keyword_contributor_test.dart
@@ -333,13 +333,15 @@
addTestSource('main() {foo(() ^ {}}}');
await computeSuggestions();
assertSuggestKeywords([],
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_anonymous_function_async2() async {
addTestSource('main() {foo(() a^ {}}}');
await computeSuggestions();
- assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_anonymous_function_async3() async {
@@ -348,6 +350,20 @@
assertSuggestKeywords([]);
}
+ test_anonymous_function_async4() async {
+ addTestSource('main() {foo(() ^ => 2}}');
+ await computeSuggestions();
+ assertSuggestKeywords([],
+ pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ }
+
+ test_anonymous_function_async5() async {
+ addTestSource('main() {foo(() ^}}');
+ await computeSuggestions();
+ assertSuggestKeywords(EXPRESSION_START_NO_INSTANCE,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
+ }
+
test_argument() async {
addTestSource('main() {foo(^);}');
await computeSuggestions();
@@ -651,35 +667,40 @@
addTestSource('main()^');
await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_function_async2() async {
addTestSource('main()^{}');
await computeSuggestions();
assertSuggestKeywords([],
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_function_async3() async {
addTestSource('main()a^');
await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_function_async4() async {
addTestSource('main()a^{}');
await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_function_async5() async {
addTestSource('main()a^ Foo foo;');
await computeSuggestions();
assertSuggestKeywords(DECLARATION_KEYWORDS,
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_function_body_inClass_constructorInitializer() async {
@@ -706,6 +727,19 @@
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
}
+ test_function_body_inClass_constructorInitializer_async_star() async {
+ addTestSource(r'''
+ foo(p) {}
+ class A {
+ final f;
+ A() : f = foo(() async* {^});
+ }
+ ''');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
test_function_body_inClass_field() async {
addTestSource(r'''
class A {
@@ -756,6 +790,21 @@
assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
}
+ test_function_body_inClass_methodBody_inFunction_async_star() async {
+ addTestSource(r'''
+ class A {
+ m() {
+ f() {
+ f2() async* {^};
+ };
+ }
+ }
+ ''');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_IN_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
test_function_body_inUnit() async {
addTestSource('main() {^}');
await computeSuggestions();
@@ -774,6 +823,34 @@
assertSuggestKeywords(STMT_START_OUTSIDE_CLASS, pseudoKeywords: ['await']);
}
+ test_function_body_inUnit_async_star() async {
+ addTestSource('main() async* {n^}');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
+ test_function_body_inUnit_async_star2() async {
+ addTestSource('main() async* {n^ foo}');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
+ test_function_body_inUnit_sync_star() async {
+ addTestSource('main() sync* {n^}');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
+ test_function_body_inUnit_sync_star2() async {
+ addTestSource('main() sync* {n^ foo}');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_OUTSIDE_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
test_if_expression_in_class() async {
addTestSource('class A {foo() {if (^) }}');
await computeSuggestions();
@@ -1098,38 +1175,44 @@
test_method_async() async {
addTestSource('class A { foo() ^}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_async2() async {
addTestSource('class A { foo() ^{}}');
await computeSuggestions();
assertSuggestKeywords([],
- pseudoKeywords: ['async'], relevance: DART_RELEVANCE_HIGH);
+ pseudoKeywords: ['async', 'async*', 'sync*'],
+ relevance: DART_RELEVANCE_HIGH);
}
test_method_async3() async {
addTestSource('class A { foo() a^}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_async4() async {
addTestSource('class A { foo() a^{}}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_async5() async {
addTestSource('class A { foo() ^ Foo foo;}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_async6() async {
addTestSource('class A { foo() a^ Foo foo;}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_async7() async {
@@ -1142,7 +1225,8 @@
test_method_async8() async {
addTestSource('class A { foo() a^ Foo foo;}');
await computeSuggestions();
- assertSuggestKeywords(CLASS_BODY_KEYWORDS, pseudoKeywords: ['async']);
+ assertSuggestKeywords(CLASS_BODY_KEYWORDS,
+ pseudoKeywords: ['async', 'async*', 'sync*']);
}
test_method_body() async {
@@ -1175,6 +1259,13 @@
assertSuggestKeywords(STMT_START_IN_CLASS, pseudoKeywords: ['await']);
}
+ test_method_body_async_star() async {
+ addTestSource('class A { foo() async* {^}}');
+ await computeSuggestions();
+ assertSuggestKeywords(STMT_START_IN_CLASS,
+ pseudoKeywords: ['await', 'yield', 'yield*']);
+ }
+
test_method_body_async2() async {
addTestSource('class A { foo() async => ^}');
await computeSuggestions();
diff --git a/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.dart
new file mode 100644
index 0000000..ac38fa6
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/library_member_contributor_test.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 test.services.completion.contributor.dart.library_member;
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/library_member_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(LibraryMemberContributorTest);
+}
+
+@reflectiveTest
+class LibraryMemberContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new LibraryMemberContributor();
+ }
+
+ test_libraryPrefix() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^}');
+ await computeSuggestions();
+ assertSuggestClass('Future');
+ assertNotSuggested('loadLibrary');
+ }
+
+ test_libraryPrefix_cascade() async {
+ addTestSource('''
+ import "dart:math" as math;
+ main() {math..^}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_libraryPrefix_cascade2() async {
+ addTestSource('''
+ import "dart:math" as math;
+ main() {math.^.}''');
+ await computeSuggestions();
+ assertSuggestFunction('min', 'num');
+ }
+
+ test_libraryPrefix_cascade3() async {
+ addTestSource('''
+ import "dart:math" as math;
+ main() {math..^a}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_libraryPrefix_cascade4() async {
+ addTestSource('''
+ import "dart:math" as math;
+ main() {math.^.a}''');
+ await computeSuggestions();
+ assertSuggestFunction('min', 'num');
+ }
+
+ test_libraryPrefix2() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^ print("f")}');
+ await computeSuggestions();
+ assertSuggestClass('Future');
+ }
+
+ test_libraryPrefix3() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {new bar.F^ print("f")}');
+ await computeSuggestions();
+ assertSuggestConstructor('Future');
+ assertSuggestConstructor('Future.delayed');
+ }
+
+ test_libraryPrefix_deferred() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" deferred as bar; foo() {bar.^}');
+ await computeSuggestions();
+ assertSuggestClass('Future');
+ assertSuggestFunction('loadLibrary', 'Future<dynamic>');
+ }
+
+ test_libraryPrefix_deferred_inPart() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ var libFile = '${testFile.substring(0, testFile.length - 5)}A.dart';
+ addSource(
+ libFile,
+ '''
+ library testA;
+ import "dart:async" deferred as bar;
+ part "$testFile";''');
+ addTestSource('part of testA; foo() {bar.^}');
+ // Assume that libraries containing has been computed for part files
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ assertSuggestClass('Future');
+ assertSuggestFunction('loadLibrary', 'Future<dynamic>');
+ }
+
+ test_libraryPrefix_with_exports() async {
+ addSource('/libA.dart', 'library libA; class A { }');
+ addSource('/libB.dart', 'library libB; export "/libA.dart"; class B { }');
+ addTestSource('import "/libB.dart" as foo; main() {foo.^} class C { }');
+ await computeSuggestions();
+ assertSuggestClass('B');
+ assertSuggestClass('A');
+ }
+
+ test_PrefixedIdentifier_library() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addTestSource('''
+ import "/testB.dart" as b;
+ var T2;
+ class A { }
+ main() {b.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('X');
+ assertSuggestClass('Y');
+ assertSuggestTopLevelVar('T1', null);
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_PrefixedIdentifier_library_inPart() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ var libFile = '${testFile.substring(0, testFile.length - 5)}A.dart';
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addSource(
+ libFile,
+ '''
+ library testA;
+ import "/testB.dart" as b;
+ part "$testFile";
+ var T2;
+ class A { }''');
+ addTestSource('''
+ part of testA;
+ main() {b.^}''');
+ // Assume that libraries containing has been computed for part files
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('X');
+ assertSuggestClass('Y');
+ assertSuggestTopLevelVar('T1', null);
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_PrefixedIdentifier_library_typesOnly() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addTestSource('''
+ import "/testB.dart" as b;
+ var T2;
+ class A { }
+ foo(b.^ f) {}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('X');
+ assertSuggestClass('Y');
+ assertNotSuggested('T1');
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_PrefixedIdentifier_library_typesOnly2() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ var T1;
+ class X { }
+ class Y { }''');
+ addTestSource('''
+ import "/testB.dart" as b;
+ var T2;
+ class A { }
+ foo(b.^) {}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestClass('X');
+ assertSuggestClass('Y');
+ assertNotSuggested('T1');
+ assertNotSuggested('T2');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_PrefixedIdentifier_parameter() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ class _W {M y; var _z;}
+ class X extends _W {}
+ class M{}''');
+ addTestSource('''
+ import "/testB.dart";
+ foo(X x) {x.^}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_PrefixedIdentifier_prefix() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addSource(
+ '/testA.dart',
+ '''
+ class A {static int bar = 10;}
+ _B() {}''');
+ addTestSource('''
+ import "/testA.dart";
+ class X {foo(){A^.bar}}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart
new file mode 100644
index 0000000..2de1f23
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/library_prefix_contributor_test.dart
@@ -0,0 +1,377 @@
+// 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.contributor.dart.library_prefix;
+
+import 'package:analysis_server/src/protocol_server.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/library_prefix_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(LibraryPrefixContributorTest);
+}
+
+@reflectiveTest
+class LibraryPrefixContributorTest extends DartCompletionContributorTest {
+ void assertSuggestLibraryPrefixes(List<String> expectedPrefixes) {
+ for (String prefix in expectedPrefixes) {
+ CompletionSuggestion cs = assertSuggest(prefix,
+ csKind: CompletionSuggestionKind.IDENTIFIER,
+ relevance: DART_RELEVANCE_DEFAULT);
+ Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(ElementKind.LIBRARY));
+ expect(element.parameters, isNull);
+ expect(element.returnType, isNull);
+ assertHasNoParameterInfo(cs);
+ }
+ if (suggestions.length != expectedPrefixes.length) {
+ failedCompletion('expected only ${expectedPrefixes.length} suggestions');
+ }
+ }
+
+ @override
+ DartCompletionContributor createContributor() {
+ return new LibraryPrefixContributor();
+ }
+
+ test_Block() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+export "dart:math" hide max;
+class A {int x;}
+@deprecated D1() {int x;}
+class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+String T1;
+var _T2;
+class C { }
+class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+class EE { }
+class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+class H { }
+int T3;
+var _T4;'''); // not imported
+ addTestSource('''
+import "/testAB.dart";
+import "/testCD.dart" hide D;
+import "/testEEF.dart" show EE;
+import "/testG.dart" as g;
+int T5;
+var _T6;
+String get T7 => 'hello';
+set T8(int value) { partT8() {} }
+Z D2() {int x;}
+class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ ^ var r;
+ }
+ void b() { }}
+class Z { }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['g']);
+ }
+
+ test_Block_final_final() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+export "dart:math" hide max;
+class A {int x;}
+@deprecated D1() {int x;}
+class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+String T1;
+var _T2;
+class C { }
+class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+class EE { }
+class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+class H { }
+int T3;
+var _T4;'''); // not imported
+ addTestSource('''
+import "/testAB.dart";
+import "/testCD.dart" hide D;
+import "/testEEF.dart" show EE;
+import "/testG.dart" as g;
+int T5;
+var _T6;
+String get T7 => 'hello';
+set T8(int value) { partT8() {} }
+Z D2() {int x;}
+class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ final ^
+ final var f;
+ localF(int arg1) { }
+ {var x;}
+ }
+ void b() { }}
+class Z { }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['g']);
+ }
+
+ test_Block_final_var() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+export "dart:math" hide max;
+class A {int x;}
+@deprecated D1() {int x;}
+class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+String T1;
+var _T2;
+class C { }
+class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+class EE { }
+class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+class H { }
+int T3;
+var _T4;'''); // not imported
+ addTestSource('''
+import "/testAB.dart";
+import "/testCD.dart" hide D;
+import "/testEEF.dart" show EE;
+import "/testG.dart" as g;
+int T5;
+var _T6;
+String get T7 => 'hello';
+set T8(int value) { partT8() {} }
+Z D2() {int x;}
+class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ final ^
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ }
+ void b() { }}
+class Z { }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['g']);
+ }
+
+ test_ClassDeclaration_body() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as x;
+@deprecated class A {^}
+class _B {}
+A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['x']);
+ }
+
+ test_ClassDeclaration_body_final() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as x;
+class A {final ^}
+class _B {}
+A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['x']);
+ }
+
+ test_ClassDeclaration_body_final_field() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as x;
+class A {final ^ A(){}}
+class _B {}
+A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['x']);
+ }
+
+ test_ClassDeclaration_body_final_field2() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as Soo;
+class A {final S^ A();}
+class _B {}
+A Sew;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertSuggestLibraryPrefixes(['Soo']);
+ }
+
+ test_ClassDeclaration_body_final_final() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as x;
+class A {final ^ final foo;}
+class _B {}
+A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['x']);
+ }
+
+ test_ClassDeclaration_body_final_var() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+class B { }''');
+ addTestSource('''
+import "testB.dart" as x;
+class A {final ^ var foo;}
+class _B {}
+A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestLibraryPrefixes(['x']);
+ }
+
+ test_InstanceCreationExpression() async {
+ addSource(
+ '/testA.dart',
+ '''
+class A {foo(){var f; {var x;}}}
+class B {B(this.x, [String boo]) { } int x;}
+class C {C.bar({boo: 'hoo', int z: 0}) { } }''');
+ addTestSource('''
+import "/testA.dart" as t;
+import "dart:math" as math;
+main() {new ^ String x = "hello";}''');
+ await computeSuggestions();
+ assertSuggestLibraryPrefixes(['math', 't']);
+ }
+
+ test_InstanceCreationExpression2() async {
+ addTestSource('import "dart:convert" as json;f() {var x=new js^}');
+ await computeSuggestions();
+ assertSuggestLibraryPrefixes(['json']);
+ }
+
+ test_InstanceCreationExpression_inPart() async {
+ addSource(
+ '/testA.dart',
+ '''
+class A {foo(){var f; {var x;}}}
+class B {B(this.x, [String boo]) { } int x;}
+class C {C.bar({boo: 'hoo', int z: 0}) { } }''');
+ addSource(
+ '/testB.dart',
+ '''
+library testB;
+import "/testA.dart" as t;
+import "dart:math" as math;
+part "$testFile"
+main() {new ^ String x = "hello";}''');
+ addTestSource('''
+part of testB;
+main() {new ^ String x = "hello";}''');
+ await computeLibrariesContaining();
+ await computeSuggestions();
+ assertSuggestLibraryPrefixes(['math', 't']);
+ }
+
+ test_InstanceCreationExpression_inPart_detached() async {
+ addSource(
+ '/testA.dart',
+ '''
+class A {foo(){var f; {var x;}}}
+class B {B(this.x, [String boo]) { } int x;}
+class C {C.bar({boo: 'hoo', int z: 0}) { } }''');
+ addSource(
+ '/testB.dart',
+ '''
+library testB;
+import "/testA.dart" as t;
+import "dart:math" as math;
+//part "$testFile"
+main() {new ^ String x = "hello";}''');
+ addTestSource('''
+//part of testB;
+main() {new ^ String x = "hello";}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart
new file mode 100644
index 0000000..0ac517b
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/named_constructor_contributor_test.dart
@@ -0,0 +1,182 @@
+// 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.contributor.dart.named_constructor;
+
+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/named_constructor_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(NamedConstructorContributorTest);
+}
+
+@reflectiveTest
+class NamedConstructorContributorTest extends DartCompletionContributorTest {
+ CompletionSuggestion assertSuggestNamedConstructor(
+ String name, String returnType,
+ [int relevance = DART_RELEVANCE_DEFAULT,
+ CompletionSuggestionKind kind = CompletionSuggestionKind.INVOCATION]) {
+ CompletionSuggestion cs =
+ assertSuggest(name, csKind: kind, relevance: relevance);
+ Element element = cs.element;
+ expect(element, isNotNull);
+ expect(element.kind, equals(ElementKind.CONSTRUCTOR));
+ expect(element.name, equals(name));
+ String param = element.parameters;
+ expect(param, isNotNull);
+ expect(param[0], equals('('));
+ expect(param[param.length - 1], equals(')'));
+ expect(element.returnType, equals(returnType));
+ assertHasParameterInfo(cs);
+ return cs;
+ }
+
+ @override
+ DartCompletionContributor createContributor() {
+ return new NamedConstructorContributor();
+ }
+
+ test_ConstructorName_importedClass() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ Source libSource = addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ var m;
+ main() {new X.^}''');
+ // Assume that imported libraries are resolved
+ await resolveLibraryUnit(libSource);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestNamedConstructor('c', 'X');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_importedClass_unresolved() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ var m;
+ main() {new X.^}''');
+ // Assume that imported libraries are NOT resolved
+ //await resolveLibraryUnit(libSource);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestNamedConstructor('c', 'X');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_importedFactory() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ Source libSource = addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {factory X.c(); factory X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ var m;
+ main() {new X.^}''');
+ // Assume that imported libraries are resolved
+ await resolveLibraryUnit(libSource);
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestNamedConstructor('c', 'X');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_importedFactory2() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ main() {new String.fr^omCharCodes([]);}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 13);
+ assertSuggestNamedConstructor('fromCharCodes', 'String');
+ assertNotSuggested('isEmpty');
+ assertNotSuggested('isNotEmpty');
+ assertNotSuggested('length');
+ assertNotSuggested('Object');
+ assertNotSuggested('String');
+ }
+
+ test_ConstructorName_localClass() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestNamedConstructor('c', 'X');
+ assertSuggestNamedConstructor('_d', 'X');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_localFactory() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ int T1;
+ F1() { }
+ class X {factory X.c(); factory X._d(); z() {}}
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestNamedConstructor('c', 'X');
+ assertSuggestNamedConstructor('_d', 'X');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
new file mode 100644
index 0000000..6efd8ab
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/static_member_contributor_test.dart
@@ -0,0 +1,289 @@
+// 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.static_member;
+
+import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
+import 'package:analysis_server/src/services/completion/dart/static_member_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(StaticMemberContributorTest);
+}
+
+@reflectiveTest
+class StaticMemberContributorTest extends DartCompletionContributorTest {
+ @override
+ DartCompletionContributor createContributor() {
+ return new StaticMemberContributor();
+ }
+
+ fail_enumConst_deprecated() async {
+ addTestSource('@deprecated enum E { one, two } main() {E.^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ // TODO(danrubel) Investigate why enum suggestion is not marked
+ // as deprecated if enum ast element is deprecated
+ assertSuggestEnumConst('one', isDeprecated: true);
+ assertSuggestEnumConst('two', isDeprecated: true);
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>', isDeprecated: true);
+ }
+
+ test_PrefixedIdentifier_class_const() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement Block
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ class I {
+ static const scI = 'boo';
+ X get f => new A();
+ get _g => new A();}
+ class B implements I {
+ static const int scB = 12;
+ var b; X _c;
+ X get d => new A();get _e => new A();
+ set s1(I x) {} set _s2(I x) {}
+ m(X x) {} I _n(X x) {}}
+ class X{}''');
+ addTestSource('''
+ import "/testB.dart";
+ class A extends B {
+ static const String scA = 'foo';
+ w() { }}
+ main() {A.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('scA', 'String');
+ assertNotSuggested('scB');
+ assertNotSuggested('scI');
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('d');
+ assertNotSuggested('_e');
+ assertNotSuggested('f');
+ assertNotSuggested('_g');
+ assertNotSuggested('s1');
+ assertNotSuggested('_s2');
+ assertNotSuggested('m');
+ assertNotSuggested('_n');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('X');
+ assertNotSuggested('w');
+ assertNotSuggested('Object');
+ assertNotSuggested('==');
+ }
+
+ test_enumConst() async {
+ addTestSource('enum E { one, two } main() {E.^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestEnumConst('one');
+ assertSuggestEnumConst('two');
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>');
+ }
+
+ test_enumConst2() async {
+ addTestSource('enum E { one, two } main() {E.o^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestEnumConst('one');
+ assertSuggestEnumConst('two');
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>');
+ }
+
+ test_enumConst3() async {
+ addTestSource('enum E { one, two } main() {E.^ int g;}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestEnumConst('one');
+ assertSuggestEnumConst('two');
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>');
+ }
+
+ test_enumConst_cascade1() async {
+ addTestSource('enum E { one, two } main() {E..^}');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_enumConst_cascade2() async {
+ addTestSource('enum E { one, two } main() {E.^.}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestEnumConst('one');
+ assertSuggestEnumConst('two');
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>');
+ }
+
+ test_enumConst_cascade3() async {
+ addTestSource('enum E { one, two } main() {E..o^}');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_enumConst_cascade4() async {
+ addTestSource('enum E { one, two } main() {E.^.o}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertSuggestEnumConst('one');
+ assertSuggestEnumConst('two');
+ assertNotSuggested('index');
+ assertSuggestField('values', 'List<E>');
+ }
+
+ test_keyword() async {
+ addTestSource('class C { static C get instance => null; } main() {C.in^}');
+ await computeSuggestions();
+ assertSuggestGetter('instance', 'C');
+ }
+
+ test_only_static() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^}''');
+ await computeSuggestions();
+ assertNotSuggested('b1');
+ assertNotSuggested('f1');
+ assertSuggestField('f2', 'int');
+ assertNotSuggested('m1');
+ assertSuggestMethod('m2', 'C', null);
+ }
+
+ test_only_static2() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^ print("something");}''');
+ await computeSuggestions();
+ assertNotSuggested('b1');
+ assertNotSuggested('f1');
+ assertSuggestField('f2', 'int');
+ assertNotSuggested('m1');
+ assertSuggestMethod('m2', 'C', null);
+ }
+
+ test_only_static_cascade1() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C..^}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_only_static_cascade2() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^.}''');
+ await computeSuggestions();
+ assertNotSuggested('b1');
+ assertNotSuggested('f1');
+ assertSuggestField('f2', 'int');
+ assertNotSuggested('m1');
+ assertSuggestMethod('m2', 'C', null);
+ }
+
+ test_only_static_cascade3() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C..m^()}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_only_static_cascade4() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class B {
+ static int b1;
+}
+class C extends B {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^.m()}''');
+ await computeSuggestions();
+ assertNotSuggested('b1');
+ assertNotSuggested('f1');
+ assertSuggestField('f2', 'int');
+ assertNotSuggested('m1');
+ assertSuggestMethod('m2', 'C', null);
+ }
+
+ test_only_static_cascade_prefixed1() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+import "dart:async" as async;
+void main() {async.Future..w^()}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_only_static_cascade_prefixed2() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+import "dart:async" as async;
+void main() {async.Future.^.w()}''');
+ await computeSuggestions();
+ assertSuggestMethod('wait', 'Future', 'Future<dynamic>');
+ }
+}
diff --git a/pkg/analysis_server/test/services/completion/dart/test_all.dart b/pkg/analysis_server/test/services/completion/dart/test_all.dart
index 6d5c836..a9dc275 100644
--- a/pkg/analysis_server/test/services/completion/dart/test_all.dart
+++ b/pkg/analysis_server/test/services/completion/dart/test_all.dart
@@ -7,12 +7,17 @@
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 'combinator_contributor_test.dart' as combinator_test;
import 'common_usage_sorter_test.dart' as common_usage_test;
import 'field_formal_contributor_test.dart' as field_formal_contributor_test;
import 'inherited_contributor_test.dart' as inherited_contributor_test;
import 'keyword_contributor_test.dart' as keyword_test;
+import 'library_member_contributor_test.dart' as library_member_test;
+import 'library_prefix_contributor_test.dart' as library_prefix_test;
+import 'named_constructor_contributor_test.dart' as named_contributor_test;
+import 'static_member_contributor_test.dart' as static_contributor_test;
+import 'type_member_contributor_test.dart' as type_member_contributor_test;
import 'uri_contributor_test.dart' as uri_contributor_test;
/// Utility for manually running all tests.
@@ -25,6 +30,11 @@
field_formal_contributor_test.main();
inherited_contributor_test.main();
keyword_test.main();
+ library_member_test.main();
+ library_prefix_test.main();
+ named_contributor_test.main();
+ static_contributor_test.main();
+ type_member_contributor_test.main();
uri_contributor_test.main();
});
}
diff --git a/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
new file mode 100644
index 0000000..8d176b8
--- /dev/null
+++ b/pkg/analysis_server/test/services/completion/dart/type_member_contributor_test.dart
@@ -0,0 +1,4157 @@
+// 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.contributor.dart.type_member;
+
+import 'dart:async';
+
+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/type_member_contributor.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../../utils.dart';
+import 'completion_contributor_util.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(TypeMemberContributorTest);
+}
+
+@reflectiveTest
+class TypeMemberContributorTest extends DartCompletionContributorTest {
+ /**
+ * Check whether a declaration of the form [shadower] in a derived class
+ * shadows a declaration of the form [shadowee] in a base class, for the
+ * purposes of what is shown during completion. [shouldBeShadowed] indicates
+ * whether shadowing is expected.
+ */
+ Future check_shadowing(
+ String shadower, String shadowee, bool shouldBeShadowed) async {
+ addTestSource('''
+class Base {
+ $shadowee
+}
+class Derived extends Base {
+ $shadower
+}
+void f(Derived d) {
+ d.^
+}
+''');
+ await computeSuggestions();
+ List<CompletionSuggestion> suggestionsForX = suggestions
+ .where((CompletionSuggestion s) => s.completion == 'x')
+ .toList();
+ expect(suggestionsForX, hasLength(1));
+ if (shouldBeShadowed) {
+ expect(suggestionsForX[0].declaringType, 'Derived');
+ } else {
+ expect(suggestionsForX[0].declaringType, 'Base');
+ }
+ }
+
+ fail_test_PrefixedIdentifier_trailingStmt_const_untyped() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('const g = "hello"; f() {g.^ int y = 0;}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ @override
+ DartCompletionContributor createContributor() {
+ return new TypeMemberContributor();
+ }
+
+ test_enumConst() async {
+ addTestSource('enum E { one, two } main() {E.^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertNotSuggested('index');
+ assertNotSuggested('values');
+ }
+
+ test_enumConst2() async {
+ addTestSource('enum E { one, two } main() {E.o^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertNotSuggested('index');
+ assertNotSuggested('values');
+ }
+
+ test_enumConst3() async {
+ addTestSource('enum E { one, two } main() {E.^ int g;}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertNotSuggested('index');
+ assertNotSuggested('values');
+ }
+
+ test_enumConst_index() async {
+ addTestSource('enum E { one, two } main() {E.one.^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertSuggestField('index', 'int');
+ assertNotSuggested('values');
+ }
+
+ test_enumConst_index2() async {
+ addTestSource('enum E { one, two } main() {E.one.i^}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertSuggestField('index', 'int');
+ assertNotSuggested('values');
+ }
+
+ test_enumConst_index3() async {
+ addTestSource('enum E { one, two } main() {E.one.^ int g;}');
+ await computeSuggestions();
+ assertNotSuggested('E');
+ assertNotSuggested('one');
+ assertNotSuggested('two');
+ assertSuggestField('index', 'int');
+ assertNotSuggested('values');
+ }
+
+ test_generic_field() async {
+ addTestSource('''
+class C<T> {
+ T t;
+}
+void f(C<int> c) {
+ c.^
+}
+''');
+ await computeSuggestions();
+ assertSuggestField('t', 'int');
+ }
+
+ test_generic_getter() async {
+ addTestSource('''
+class C<T> {
+ T get t => null;
+}
+void f(C<int> c) {
+ c.^
+}
+''');
+ await computeSuggestions();
+ assertSuggestGetter('t', 'int');
+ }
+
+ test_generic_method() async {
+ addTestSource('''
+class C<T> {
+ T m(T t) {}
+}
+void f(C<int> c) {
+ c.^
+}
+''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'int');
+ expect(suggestion.parameterTypes[0], 'int');
+ expect(suggestion.element.returnType, 'int');
+ expect(suggestion.element.parameters, '(int t)');
+ }
+
+ test_generic_setter() async {
+ addTestSource('''
+class C<T> {
+ set t(T value) {}
+}
+void f(C<int> c) {
+ c.^
+}
+''');
+ await computeSuggestions();
+ // TODO(paulberry): modify assertSuggestSetter so that we can pass 'int'
+ // as a parmeter to it, and it will check the appropriate field in
+ // the suggestion object.
+ CompletionSuggestion suggestion = assertSuggestSetter('t');
+ expect(suggestion.element.parameters, '(int value)');
+ }
+
+ test_keyword() async {
+ addTestSource('class C { static C get instance => null; } main() {C.in^}');
+ await computeSuggestions();
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('instance');
+ }
+
+ test_libraryPrefix() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^}');
+ await computeSuggestions();
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('Future');
+ assertNotSuggested('loadLibrary');
+ }
+
+ test_libraryPrefix2() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^ print("f")}');
+ await computeSuggestions();
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('Future');
+ }
+
+ test_libraryPrefix3() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {new bar.F^ print("f")}');
+ await computeSuggestions();
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('Future');
+ assertNotSuggested('Future.delayed');
+ }
+
+ test_libraryPrefix_deferred() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" deferred as bar; foo() {bar.^}');
+ await computeSuggestions();
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('Future');
+ assertNotSuggested('loadLibrary');
+ }
+
+ test_libraryPrefix_with_exports() async {
+ addSource('/libA.dart', 'library libA; class A { }');
+ addSource('/libB.dart', 'library libB; export "/libA.dart"; class B { }');
+ addTestSource('import "/libB.dart" as foo; main() {foo.^} class C { }');
+ await computeSuggestions();
+ // Suggested by LibraryMemberContributor
+ assertNotSuggested('B');
+ assertNotSuggested('A');
+ }
+
+ test_local() async {
+ addTestSource('foo() {String x = "bar"; x.^}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ test_local_is() async {
+ addTestSource('foo() {var x; if (x is String) x.^}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ test_local_propogatedType() async {
+ addTestSource('foo() {var x = "bar"; x.^}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ test_method_parameters_mixed_required_and_named() async {
+ addTestSource('''
+class C {
+ void m(x, {int y}) {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, hasLength(2));
+ expect(suggestion.parameterNames[0], 'x');
+ expect(suggestion.parameterTypes[0], 'dynamic');
+ expect(suggestion.parameterNames[1], 'y');
+ expect(suggestion.parameterTypes[1], 'int');
+ expect(suggestion.requiredParameterCount, 1);
+ expect(suggestion.hasNamedParameters, true);
+ }
+
+ test_method_parameters_mixed_required_and_positional() async {
+ addTestSource('''
+class C {
+ void m(x, [int y]) {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, hasLength(2));
+ expect(suggestion.parameterNames[0], 'x');
+ expect(suggestion.parameterTypes[0], 'dynamic');
+ expect(suggestion.parameterNames[1], 'y');
+ expect(suggestion.parameterTypes[1], 'int');
+ expect(suggestion.requiredParameterCount, 1);
+ expect(suggestion.hasNamedParameters, false);
+ }
+
+ test_method_parameters_named() async {
+ addTestSource('''
+class C {
+ void m({x, int y}) {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, hasLength(2));
+ expect(suggestion.parameterNames[0], 'x');
+ expect(suggestion.parameterTypes[0], 'dynamic');
+ expect(suggestion.parameterNames[1], 'y');
+ expect(suggestion.parameterTypes[1], 'int');
+ expect(suggestion.requiredParameterCount, 0);
+ expect(suggestion.hasNamedParameters, true);
+ }
+
+ test_method_parameters_none() async {
+ addTestSource('''
+class C {
+ void m() {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, isEmpty);
+ expect(suggestion.parameterTypes, isEmpty);
+ expect(suggestion.requiredParameterCount, 0);
+ expect(suggestion.hasNamedParameters, false);
+ }
+
+ test_method_parameters_positional() async {
+ addTestSource('''
+class C {
+ void m([x, int y]) {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, hasLength(2));
+ expect(suggestion.parameterNames[0], 'x');
+ expect(suggestion.parameterTypes[0], 'dynamic');
+ expect(suggestion.parameterNames[1], 'y');
+ expect(suggestion.parameterTypes[1], 'int');
+ expect(suggestion.requiredParameterCount, 0);
+ expect(suggestion.hasNamedParameters, false);
+ }
+
+ test_method_parameters_required() async {
+ addTestSource('''
+class C {
+ void m(x, int y) {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestMethod('m', 'C', 'void');
+ expect(suggestion.parameterNames, hasLength(2));
+ expect(suggestion.parameterNames[0], 'x');
+ expect(suggestion.parameterTypes[0], 'dynamic');
+ expect(suggestion.parameterNames[1], 'y');
+ expect(suggestion.parameterTypes[1], 'int');
+ expect(suggestion.requiredParameterCount, 2);
+ expect(suggestion.hasNamedParameters, false);
+ }
+
+ test_no_parameters_field() async {
+ addTestSource('''
+class C {
+ int x;
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestField('x', 'int');
+ assertHasNoParameterInfo(suggestion);
+ }
+
+ test_no_parameters_getter() async {
+ addTestSource('''
+class C {
+ int get x => null;
+}
+void main() {int y = new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestGetter('x', 'int');
+ assertHasNoParameterInfo(suggestion);
+ }
+
+ test_no_parameters_setter() async {
+ addTestSource('''
+class C {
+ set x(int value) {};
+}
+void main() {int y = new C().^}''');
+ await computeSuggestions();
+ CompletionSuggestion suggestion = assertSuggestSetter('x');
+ assertHasNoParameterInfo(suggestion);
+ }
+
+ test_only_instance() async {
+ // SimpleIdentifier PropertyAccess ExpressionStatement
+ addTestSource('''
+class C {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {new C().^}''');
+ await computeSuggestions();
+ assertSuggestField('f1', 'int');
+ assertNotSuggested('f2');
+ assertSuggestMethod('m1', 'C', null);
+ assertNotSuggested('m2');
+ }
+
+ test_only_instance2() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('''
+class C {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {new C().^ print("something");}''');
+ await computeSuggestions();
+ assertSuggestField('f1', 'int');
+ assertNotSuggested('f2');
+ assertSuggestMethod('m1', 'C', null);
+ assertNotSuggested('m2');
+ }
+
+ test_only_static() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('''
+class C {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^}''');
+ await computeSuggestions();
+ assertNotSuggested('f1');
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('f2');
+ assertNotSuggested('m1');
+ assertNotSuggested('m2');
+ }
+
+ test_only_static2() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('''
+class C {
+ int f1;
+ static int f2;
+ m1() {}
+ static m2() {}
+}
+void main() {C.^ print("something");}''');
+ await computeSuggestions();
+ assertNotSuggested('f1');
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('f2');
+ assertNotSuggested('m1');
+ assertNotSuggested('m2');
+ }
+
+ test_param() async {
+ addTestSource('foo(String x) {x.^}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ test_param_is() async {
+ addTestSource('foo(x) {if (x is String) x.^}');
+ await computeSuggestions();
+ assertSuggestGetter('length', 'int');
+ }
+
+ test_shadowing_field_over_field() =>
+ check_shadowing('int x;', 'int x;', true);
+
+ test_shadowing_field_over_getter() =>
+ check_shadowing('int x;', 'int get x => null;', true);
+
+ test_shadowing_field_over_method() =>
+ check_shadowing('int x;', 'void x() {}', true);
+
+ test_shadowing_field_over_setter() =>
+ check_shadowing('int x;', 'set x(int value) {}', true);
+
+ test_shadowing_getter_over_field() =>
+ check_shadowing('int get x => null;', 'int x;', false);
+
+ test_shadowing_getter_over_getter() =>
+ check_shadowing('int get x => null;', 'int get x => null;', true);
+
+ test_shadowing_getter_over_method() =>
+ check_shadowing('int get x => null;', 'void x() {}', true);
+
+ test_shadowing_getter_over_setter() =>
+ check_shadowing('int get x => null;', 'set x(int value) {}', false);
+
+ test_shadowing_method_over_field() =>
+ check_shadowing('void x() {}', 'int x;', true);
+
+ test_shadowing_method_over_getter() =>
+ check_shadowing('void x() {}', 'int get x => null;', true);
+
+ test_shadowing_method_over_method() =>
+ check_shadowing('void x() {}', 'void x() {}', true);
+
+ test_shadowing_method_over_setter() =>
+ check_shadowing('void x() {}', 'set x(int value) {}', true);
+
+ test_shadowing_mixin_order() async {
+ addTestSource('''
+class Base {
+}
+class Mixin1 {
+ void f() {}
+}
+class Mixin2 {
+ void f() {}
+}
+class Derived extends Base with Mixin1, Mixin2 {
+}
+void test(Derived d) {
+ d.^
+}
+''');
+ await computeSuggestions();
+ // Note: due to dartbug.com/22069, analyzer currently analyzes mixins in
+ // reverse order. The correct order is that Derived inherits from
+ // "Base with Mixin1, Mixin2", which inherits from "Base with Mixin1",
+ // which inherits from "Base". So the definition of f in Mixin2 should
+ // shadow the definition in Mixin1.
+ assertSuggestMethod('f', 'Mixin2', 'void');
+ }
+
+ test_shadowing_mixin_over_superclass() async {
+ addTestSource('''
+class Base {
+ void f() {}
+}
+class Mixin {
+ void f() {}
+}
+class Derived extends Base with Mixin {
+}
+void test(Derived d) {
+ d.^
+}
+''');
+ await computeSuggestions();
+ assertSuggestMethod('f', 'Mixin', 'void');
+ }
+
+ test_shadowing_setter_over_field() =>
+ check_shadowing('set x(int value) {}', 'int x;', false);
+
+ test_shadowing_setter_over_getter() =>
+ check_shadowing('set x(int value) {}', 'int get x => null;', false);
+
+ test_shadowing_setter_over_method() =>
+ check_shadowing('set x(int value) {}', 'void x() {}', true);
+
+ test_shadowing_setter_over_setter() =>
+ check_shadowing('set x(int value) {}', 'set x(int value) {}', true);
+
+ test_shadowing_superclass_over_interface() async {
+ addTestSource('''
+class Base {
+ void f() {}
+}
+class Interface {
+ void f() {}
+}
+class Derived extends Base implements Interface {
+}
+void test(Derived d) {
+ d.^
+}
+''');
+ await computeSuggestions();
+ assertSuggestMethod('f', 'Base', 'void');
+ }
+
+ test_super() async {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('''
+class C3 {
+ int fi3;
+ static int fs3;
+ m() {}
+ mi3() {}
+ static ms3() {}
+}
+class C2 {
+ int fi2;
+ static int fs2;
+ m() {}
+ mi2() {}
+ static ms2() {}
+}
+class C1 extends C2 implements C3 {
+ int fi1;
+ static int fs1;
+ m() {super.^}
+ mi1() {}
+ static ms1() {}
+}''');
+ await computeSuggestions();
+ assertNotSuggested('fi1');
+ assertNotSuggested('fs1');
+ assertNotSuggested('mi1');
+ assertNotSuggested('ms1');
+ assertSuggestField('fi2', 'int');
+ assertNotSuggested('fs2');
+ assertSuggestMethod('mi2', 'C2', null);
+ assertNotSuggested('ms2');
+ assertSuggestMethod('m', 'C2', null, relevance: DART_RELEVANCE_HIGH);
+ assertNotSuggested('fi3');
+ assertNotSuggested('fs3');
+ assertNotSuggested('mi3');
+ assertNotSuggested('ms3');
+ }
+
+ test_ArgumentList() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart';
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_imported_function() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ bool hasLength(int expected) { }
+ expect(arg) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_InstanceCreationExpression_functionalArg() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ class A { A(f()) { } }
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import 'dart:async';
+ import '/libA.dart';
+ class B { }
+ String bar() => true;
+ void main() {new A(^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_InstanceCreationExpression_typedefArg() async {
+ // ArgumentList InstanceCreationExpression ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ typedef Funct();
+ class A { A(Funct f) { } }
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import 'dart:async';
+ import '/libA.dart';
+ class B { }
+ String bar() => true;
+ void main() {new A(^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_local_function() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ expect(arg) { }
+ class B { }
+ String bar() => true;
+ void main() {expect(^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_local_method() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import '/libA.dart'
+ class B {
+ expect(arg) { }
+ void foo() {expect(^)}}
+ String bar() => true;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_MethodInvocation_functionalArg() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ class A { A(f()) { } }
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import 'dart:async';
+ import '/libA.dart';
+ class B { }
+ String bar(f()) => true;
+ void main() {bar(^);}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_MethodInvocation_methodArg() async {
+ // ArgumentList MethodInvocation ExpressionStatement Block
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ class A { A(f()) { } }
+ bool hasLength(int expected) { }
+ void baz() { }''');
+ addTestSource('''
+ import 'dart:async';
+ import '/libA.dart';
+ class B { String bar(f()) => true; }
+ void main() {new B().bar(^);}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
+ assertNotSuggested('hasLength');
+ assertNotSuggested('identical');
+ assertNotSuggested('B');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('main');
+ assertNotSuggested('baz');
+ assertNotSuggested('print');
+ }
+
+ test_ArgumentList_namedParam() async {
+ // SimpleIdentifier NamedExpression ArgumentList MethodInvocation
+ // ExpressionStatement
+ addSource(
+ '/libA.dart',
+ '''
+ library A;
+ bool hasLength(int expected) { }''');
+ addTestSource('''
+ import '/libA.dart'
+ String bar() => true;
+ void main() {expect(foo: ^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('bar');
+ assertNotSuggested('hasLength');
+ assertNotSuggested('main');
+ }
+
+ test_AsExpression() async {
+ // SimpleIdentifier TypeName AsExpression
+ addTestSource('''
+ class A {var b; X _c; foo() {var a; (a as ^).foo();}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_AssignmentExpression_name() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('class A {} main() {int a; int ^b = 1;}');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_AssignmentExpression_RHS() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('class A {} main() {int a; int b = ^}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_AssignmentExpression_type() async {
+ // SimpleIdentifier TypeName VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('''
+ class A {} main() {
+ int a;
+ ^ b = 1;}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('int');
+ // TODO (danrubel) When entering 1st of 2 identifiers on assignment LHS
+ // the user may be either (1) entering a type for the assignment
+ // or (2) starting a new statement.
+ // Consider suggesting only types
+ // if only spaces separates the 1st and 2nd identifiers.
+ //assertNotSuggested('a');
+ //assertNotSuggested('main');
+ //assertNotSuggested('identical');
+ }
+
+ test_AssignmentExpression_type_newline() async {
+ // SimpleIdentifier TypeName VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('''
+ class A {} main() {
+ int a;
+ ^
+ b = 1;}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('int');
+ // Allow non-types preceding an identifier on LHS of assignment
+ // if newline follows first identifier
+ // because user is probably starting a new statement
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('identical');
+ }
+
+ test_AssignmentExpression_type_partial() async {
+ // SimpleIdentifier TypeName VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('''
+ class A {} main() {
+ int a;
+ int^ b = 1;}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
+ assertNotSuggested('A');
+ assertNotSuggested('int');
+ // TODO (danrubel) When entering 1st of 2 identifiers on assignment LHS
+ // the user may be either (1) entering a type for the assignment
+ // or (2) starting a new statement.
+ // Consider suggesting only types
+ // if only spaces separates the 1st and 2nd identifiers.
+ //assertNotSuggested('a');
+ //assertNotSuggested('main');
+ //assertNotSuggested('identical');
+ }
+
+ test_AssignmentExpression_type_partial_newline() async {
+ // SimpleIdentifier TypeName VariableDeclarationList
+ // VariableDeclarationStatement Block
+ addTestSource('''
+ class A {} main() {
+ int a;
+ i^
+ b = 1;}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('A');
+ assertNotSuggested('int');
+ // Allow non-types preceding an identifier on LHS of assignment
+ // if newline follows first identifier
+ // because user is probably starting a new statement
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('identical');
+ }
+
+ test_AwaitExpression() async {
+ // SimpleIdentifier AwaitExpression ExpressionStatement
+ addTestSource('''
+ class A {int x; int y() => 0;}
+ main() async {A a; await ^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_BinaryExpression_LHS() async {
+ // SimpleIdentifier BinaryExpression VariableDeclaration
+ // VariableDeclarationList VariableDeclarationStatement
+ addTestSource('main() {int a = 1, b = ^ + 2;}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ }
+
+ test_BinaryExpression_RHS() async {
+ // SimpleIdentifier BinaryExpression VariableDeclaration
+ // VariableDeclarationList VariableDeclarationStatement
+ addTestSource('main() {int a = 1, b = 2 + ^;}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('Object');
+ assertNotSuggested('b');
+ assertNotSuggested('==');
+ }
+
+ test_Block() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ ^ var r;
+ }
+ void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+
+ assertNotSuggested('X');
+ assertNotSuggested('Z');
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('localF');
+ assertNotSuggested('f');
+ // Don't suggest locals out of scope
+ assertNotSuggested('r');
+ assertNotSuggested('x');
+ assertNotSuggested('partT8');
+
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('C');
+ assertNotSuggested('partBoo');
+ // hidden element suggested as low relevance
+ // but imported results are partially filtered
+ //assertNotSuggested('D');
+ //assertNotSuggested(
+ // 'D1', null, true, COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('D2');
+ assertNotSuggested('EE');
+ // hidden element suggested as low relevance
+ //assertNotSuggested('F');
+ assertNotSuggested('g');
+ assertNotSuggested('G');
+ //assertNotSuggested('H');
+ assertNotSuggested('Object');
+ assertNotSuggested('min');
+ assertNotSuggested('_T2');
+ //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('_T4');
+ assertNotSuggested('T5');
+ assertNotSuggested('_T6');
+ assertNotSuggested('==');
+ assertNotSuggested('T7');
+ assertNotSuggested('T8');
+ assertNotSuggested('clog');
+ assertNotSuggested('blog');
+ // TODO (danrubel) suggest HtmlElement as low relevance
+ assertNotSuggested('HtmlElement');
+ assertNotSuggested('Uri');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ }
+
+ test_Block_final() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ final ^
+ }
+ void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+
+ assertNotSuggested('X');
+ assertNotSuggested('Z');
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('localF');
+ assertNotSuggested('f');
+ // Don't suggest locals out of scope
+ assertNotSuggested('r');
+ assertNotSuggested('x');
+ assertNotSuggested('partT8');
+
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('C');
+ assertNotSuggested('partBoo');
+ // hidden element suggested as low relevance
+ // but imported results are partially filtered
+ //assertNotSuggested('D');
+ //assertNotSuggested(
+ // 'D1', null, true, COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('D2');
+ assertNotSuggested('EE');
+ // hidden element suggested as low relevance
+ //assertNotSuggested('F');
+ assertNotSuggested('g');
+ assertNotSuggested('G');
+ //assertNotSuggested('H');
+ assertNotSuggested('Object');
+ assertNotSuggested('min');
+ //assertNotSuggested(
+ // 'max',
+ // 'num',
+ // false,
+ // COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('T1');
+ assertNotSuggested('_T2');
+ //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('_T4');
+ assertNotSuggested('T5');
+ assertNotSuggested('_T6');
+ assertNotSuggested('==');
+ assertNotSuggested('T7');
+ assertNotSuggested('T8');
+ assertNotSuggested('clog');
+ assertNotSuggested('blog');
+ // TODO (danrubel) suggest HtmlElement as low relevance
+ assertNotSuggested('HtmlElement');
+ assertNotSuggested('Uri');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ }
+
+ test_Block_final2() async {
+ addTestSource('main() {final S^ v;}');
+ await computeSuggestions();
+
+ assertNotSuggested('String');
+ }
+
+ test_Block_final3() async {
+ addTestSource('main() {final ^ v;}');
+ await computeSuggestions();
+
+ assertNotSuggested('String');
+ }
+
+ test_Block_final_final() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ final ^
+ final var f;
+ localF(int arg1) { }
+ {var x;}
+ }
+ void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+
+ assertNotSuggested('X');
+ assertNotSuggested('Z');
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('localF');
+ assertNotSuggested('f');
+ // Don't suggest locals out of scope
+ assertNotSuggested('r');
+ assertNotSuggested('x');
+ assertNotSuggested('partT8');
+
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('C');
+ assertNotSuggested('partBoo');
+ // hidden element suggested as low relevance
+ // but imported results are partially filtered
+ //assertNotSuggested('D');
+ //assertNotSuggested(
+ // 'D1', null, true, COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('D2');
+ assertNotSuggested('EE');
+ // hidden element suggested as low relevance
+ //assertNotSuggested('F');
+ assertNotSuggested('g');
+ assertNotSuggested('G');
+ //assertNotSuggested('H');
+ assertNotSuggested('Object');
+ assertNotSuggested('min');
+ //assertNotSuggested(
+ // 'max',
+ // 'num',
+ // false,
+ // COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('T1');
+ assertNotSuggested('_T2');
+ //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('_T4');
+ assertNotSuggested('T5');
+ assertNotSuggested('_T6');
+ assertNotSuggested('==');
+ assertNotSuggested('T7');
+ assertNotSuggested('T8');
+ assertNotSuggested('clog');
+ assertNotSuggested('blog');
+ // TODO (danrubel) suggest HtmlElement as low relevance
+ assertNotSuggested('HtmlElement');
+ assertNotSuggested('Uri');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ }
+
+ test_Block_final_var() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ final ^
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ }
+ void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+
+ assertNotSuggested('X');
+ assertNotSuggested('Z');
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('localF');
+ assertNotSuggested('f');
+ // Don't suggest locals out of scope
+ assertNotSuggested('r');
+ assertNotSuggested('x');
+ assertNotSuggested('partT8');
+
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('C');
+ assertNotSuggested('partBoo');
+ // hidden element suggested as low relevance
+ // but imported results are partially filtered
+ //assertNotSuggested('D');
+ //assertNotSuggested(
+ // 'D1', null, true, COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('D2');
+ assertNotSuggested('EE');
+ // hidden element suggested as low relevance
+ //assertNotSuggested('F');
+ assertNotSuggested('g');
+ assertNotSuggested('G');
+ //assertNotSuggested('H');
+ assertNotSuggested('Object');
+ assertNotSuggested('min');
+ //assertNotSuggested(
+ // 'max',
+ // 'num',
+ // false,
+ // COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('T1');
+ assertNotSuggested('_T2');
+ //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('_T4');
+ assertNotSuggested('T5');
+ assertNotSuggested('_T6');
+ assertNotSuggested('==');
+ assertNotSuggested('T7');
+ assertNotSuggested('T8');
+ assertNotSuggested('clog');
+ assertNotSuggested('blog');
+ // TODO (danrubel) suggest HtmlElement as low relevance
+ assertNotSuggested('HtmlElement');
+ assertNotSuggested('Uri');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ }
+
+ test_Block_identifier_partial() async {
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B { }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ class D3 { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ Z D2() {int x;}
+ class X {a() {var f; {var x;} D^ var r;} void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+
+ assertNotSuggested('X');
+ assertNotSuggested('Z');
+ assertNotSuggested('a');
+ assertNotSuggested('b');
+ assertNotSuggested('f');
+ // Don't suggest locals out of scope
+ assertNotSuggested('r');
+ assertNotSuggested('x');
+
+ // imported elements are portially filtered
+ //assertNotSuggested('A');
+ assertNotSuggested('_B');
+ //assertNotSuggested('C');
+ // hidden element suggested as low relevance
+ assertNotSuggested('D');
+ assertNotSuggested('D1');
+ assertNotSuggested('D2');
+ // unimported elements suggested with low relevance
+ assertNotSuggested('D3');
+ //assertNotSuggested('EE');
+ // hidden element suggested as low relevance
+ //assertNotSuggested('F');
+ //assertNotSuggested('g');
+ assertNotSuggested('G');
+ //assertNotSuggested('H');
+ //assertNotSuggested('Object');
+ //assertNotSuggested('min');
+ //assertNotSuggested(
+ // 'max',
+ // 'num',
+ // false,
+ // COMPLETION_RELEVANCE_LOW);
+ //assertSuggestTopLevelVarGetterSetter('T1', 'String');
+ assertNotSuggested('_T2');
+ //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
+ assertNotSuggested('_T4');
+ //assertNotSuggested('T5');
+ //assertNotSuggested('_T6');
+ assertNotSuggested('==');
+ // TODO (danrubel) suggest HtmlElement as low relevance
+ assertNotSuggested('HtmlElement');
+ }
+
+ test_Block_inherited_imported() async {
+ // Block BlockFunctionBody MethodDeclaration ClassDeclaration
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ class F { var f1; f2() { } get f3 => 0; set f4(fx) { } var _pf; }
+ class E extends F { var e1; e2() { } }
+ class I { int i1; i2() { } }
+ class M { var m1; int m2() { } }''');
+ addTestSource('''
+ import "/testB.dart";
+ class A extends E implements I with M {a() {^}}''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // TODO (danrubel) prefer fields over getters
+ // If add `get e1;` to interface I
+ // then suggestions include getter e1 rather than field e1
+ assertNotSuggested('e1');
+ assertNotSuggested('f1');
+ assertNotSuggested('i1');
+ assertNotSuggested('m1');
+ assertNotSuggested('f3');
+ assertNotSuggested('f4');
+ assertNotSuggested('e2');
+ assertNotSuggested('f2');
+ assertNotSuggested('i2');
+ //assertNotSuggested('m2');
+ assertNotSuggested('==');
+ }
+
+ test_Block_inherited_local() async {
+ // Block BlockFunctionBody MethodDeclaration ClassDeclaration
+ addTestSource('''
+ class F { var f1; f2() { } get f3 => 0; set f4(fx) { } }
+ 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();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('e1');
+ assertNotSuggested('f1');
+ assertNotSuggested('i1');
+ assertNotSuggested('m1');
+ assertNotSuggested('f3');
+ assertNotSuggested('f4');
+ assertNotSuggested('e2');
+ assertNotSuggested('f2');
+ assertNotSuggested('i2');
+ assertNotSuggested('m2');
+ }
+
+ test_Block_local_function() async {
+ addSource(
+ '/testAB.dart',
+ '''
+ export "dart:math" hide max;
+ class A {int x;}
+ @deprecated D1() {int x;}
+ class _B {boo() { partBoo() {}} }''');
+ addSource(
+ '/testCD.dart',
+ '''
+ String T1;
+ var _T2;
+ class C { }
+ class D { }''');
+ addSource(
+ '/testEEF.dart',
+ '''
+ class EE { }
+ class F { }''');
+ addSource('/testG.dart', 'class G { }');
+ addSource(
+ '/testH.dart',
+ '''
+ class H { }
+ int T3;
+ var _T4;'''); // not imported
+ addTestSource('''
+ import "/testAB.dart";
+ import "/testCD.dart" hide D;
+ import "/testEEF.dart" show EE;
+ import "/testG.dart" as g;
+ int T5;
+ var _T6;
+ String get T7 => 'hello';
+ set T8(int value) { partT8() {} }
+ Z D2() {int x;}
+ class X {
+ int get clog => 8;
+ set blog(value) { }
+ a() {
+ var f;
+ localF(int arg1) { }
+ {var x;}
+ p^ var r;
+ }
+ void b() { }}
+ class Z { }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('partT8');
+ assertNotSuggested('partBoo');
+ assertNotSuggested('parseIPv6Address');
+ assertNotSuggested('parseHex');
+ }
+
+ test_Block_unimported() async {
+ addPackageSource('myBar', 'bar.dart', 'class Foo2 { Foo2() { } }');
+ addSource(
+ '/proj/testAB.dart', 'import "package:myBar/bar.dart"; class Foo { }');
+ testFile = '/proj/completionTest.dart';
+ addTestSource('class C {foo(){F^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('Foo');
+ // TODO(danrubel) implement
+ assertNotSuggested('Foo2');
+ assertNotSuggested('Future');
+ }
+
+ test_CascadeExpression_method1() async {
+ // PropertyAccess CascadeExpression ExpressionStatement Block
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "/testB.dart";
+ class A {var b; X _c;}
+ class X{}
+ // looks like a cascade to the parser
+ // but the user is trying to get completions for a non-cascade
+ main() {A a; a.^.z()}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('b', null);
+ assertSuggestField('_c', 'X');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('B');
+ assertNotSuggested('X');
+ assertNotSuggested('z');
+ assertNotSuggested('==');
+ }
+
+ test_CascadeExpression_selector1() async {
+ // PropertyAccess CascadeExpression ExpressionStatement Block
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "/testB.dart";
+ class A {var b; X _c;}
+ class X{}
+ // looks like a cascade to the parser
+ // but the user is trying to get completions for a non-cascade
+ main() {A a; a.^.z}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('b', null);
+ assertSuggestField('_c', 'X');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('B');
+ assertNotSuggested('X');
+ assertNotSuggested('z');
+ assertNotSuggested('==');
+ }
+
+ test_CascadeExpression_selector2() async {
+ // SimpleIdentifier PropertyAccess CascadeExpression ExpressionStatement
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "/testB.dart";
+ class A {var b; X _c;}
+ class X{}
+ main() {A a; a..^z}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 1);
+ assertSuggestField('b', null);
+ assertSuggestField('_c', 'X');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('B');
+ assertNotSuggested('X');
+ assertNotSuggested('z');
+ assertNotSuggested('==');
+ }
+
+ test_CascadeExpression_selector2_withTrailingReturn() async {
+ // PropertyAccess CascadeExpression ExpressionStatement Block
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "/testB.dart";
+ class A {var b; X _c;}
+ class X{}
+ main() {A a; a..^ return}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestField('b', null);
+ assertSuggestField('_c', 'X');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('B');
+ assertNotSuggested('X');
+ assertNotSuggested('z');
+ assertNotSuggested('==');
+ }
+
+ test_CascadeExpression_target() async {
+ // SimpleIdentifier CascadeExpression ExpressionStatement
+ addTestSource('''
+ class A {var b; X _c;}
+ class X{}
+ main() {A a; a^..b}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('X');
+ // top level results are partially filtered
+ //assertNotSuggested('Object');
+ assertNotSuggested('==');
+ }
+
+ test_CatchClause_onType() async {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^ {}}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('a');
+ assertNotSuggested('x');
+ }
+
+ test_CatchClause_onType_noBrackets() async {
+ // TypeName CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on ^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('x');
+ }
+
+ test_CatchClause_typed() async {
+ // Block CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} on E catch (e) {^}}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('e');
+ assertNotSuggested('a');
+ assertNotSuggested('Object');
+ assertNotSuggested('x');
+ }
+
+ test_CatchClause_untyped() async {
+ // Block CatchClause TryStatement
+ addTestSource('class A {a() {try{var x;} catch (e, s) {^}}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('e');
+ assertNotSuggested('s');
+ assertNotSuggested('a');
+ assertNotSuggested('Object');
+ assertNotSuggested('x');
+ }
+
+ test_ClassDeclaration_body() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as x;
+ @deprecated class A {^}
+ class _B {}
+ A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('Object');
+ assertNotSuggested('T');
+ assertNotSuggested('x');
+ }
+
+ test_ClassDeclaration_body_final() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as x;
+ class A {final ^}
+ class _B {}
+ A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('Object');
+ assertNotSuggested('T');
+ assertNotSuggested('x');
+ }
+
+ test_ClassDeclaration_body_final_field() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as x;
+ class A {final ^ A(){}}
+ class _B {}
+ A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('String');
+ assertNotSuggested('T');
+ assertNotSuggested('x');
+ }
+
+ test_ClassDeclaration_body_final_field2() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as Soo;
+ class A {final S^ A();}
+ class _B {}
+ A Sew;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('String');
+ assertNotSuggested('Sew');
+ assertNotSuggested('Soo');
+ }
+
+ test_ClassDeclaration_body_final_final() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as x;
+ class A {final ^ final foo;}
+ class _B {}
+ A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('Object');
+ assertNotSuggested('T');
+ assertNotSuggested('x');
+ }
+
+ test_ClassDeclaration_body_final_var() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testB.dart',
+ '''
+ class B { }''');
+ addTestSource('''
+ import "testB.dart" as x;
+ class A {final ^ var foo;}
+ class _B {}
+ A T;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('_B');
+ assertNotSuggested('Object');
+ assertNotSuggested('T');
+ assertNotSuggested('x');
+ }
+
+ test_Combinator_hide() async {
+ // 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 {}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_Combinator_show() async {
+ // 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 {}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_ConditionalExpression_elseExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T1 : T^}}''');
+ await computeSuggestions();
+ // top level results are partially filtered based on first char
+ assertNotSuggested('T2');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_ConditionalExpression_elseExpression_empty() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T1 : ^}}''');
+ await computeSuggestions();
+ assertNotSuggested('x');
+ assertNotSuggested('f');
+ assertNotSuggested('foo');
+ assertNotSuggested('C');
+ assertNotSuggested('F2');
+ assertNotSuggested('T2');
+ assertNotSuggested('A');
+ assertNotSuggested('F1');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_ConditionalExpression_partial_thenExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T^}}''');
+ await computeSuggestions();
+ // top level results are partially filtered based on first char
+ assertNotSuggested('T2');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_ConditionalExpression_partial_thenExpression_empty() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? ^}}''');
+ await computeSuggestions();
+ assertNotSuggested('x');
+ assertNotSuggested('f');
+ assertNotSuggested('foo');
+ assertNotSuggested('C');
+ assertNotSuggested('F2');
+ assertNotSuggested('T2');
+ assertNotSuggested('A');
+ assertNotSuggested('F1');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_ConditionalExpression_thenExpression() async {
+ // SimpleIdentifier ConditionalExpression ReturnStatement
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} return a ? T^ : c}}''');
+ await computeSuggestions();
+ // top level results are partially filtered based on first char
+ assertNotSuggested('T2');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_ConstructorName_importedClass() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ var m;
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_importedFactory() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {factory X.c(); factory X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ var m;
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_importedFactory2() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ main() {new String.fr^omCharCodes([]);}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 2);
+ expect(replacementLength, 13);
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('fromCharCodes');
+ assertNotSuggested('isEmpty');
+ assertNotSuggested('isNotEmpty');
+ assertNotSuggested('length');
+ assertNotSuggested('Object');
+ assertNotSuggested('String');
+ }
+
+ test_ConstructorName_localClass() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('_d');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_ConstructorName_localFactory() async {
+ // SimpleIdentifier PrefixedIdentifier TypeName ConstructorName
+ // InstanceCreationExpression
+ addTestSource('''
+ int T1;
+ F1() { }
+ class X {factory X.c(); factory X._d(); z() {}}
+ main() {new X.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // Suggested by NamedConstructorContributor
+ assertNotSuggested('c');
+ assertNotSuggested('_d');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_DefaultFormalParameter_named_expression() async {
+ // DefaultFormalParameter FormalParameterList MethodDeclaration
+ addTestSource('''
+ foo() { }
+ void bar() { }
+ class A {a(blat: ^) { }}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('foo');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('String');
+ assertNotSuggested('identical');
+ assertNotSuggested('bar');
+ }
+
+ test_ExpressionStatement_identifier() async {
+ // SimpleIdentifier ExpressionStatement Block
+ addSource(
+ '/testA.dart',
+ '''
+ _B F1() { }
+ class A {int x;}
+ class _B { }''');
+ addTestSource('''
+ import "/testA.dart";
+ typedef int F2(int blat);
+ class Clz = Object with Object;
+ class C {foo(){^} void bar() {}}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('F1');
+ assertNotSuggested('C');
+ assertNotSuggested('foo');
+ assertNotSuggested('bar');
+ assertNotSuggested('F2');
+ assertNotSuggested('Clz');
+ assertNotSuggested('C');
+ assertNotSuggested('x');
+ assertNotSuggested('_B');
+ }
+
+ test_ExpressionStatement_name() async {
+ // ExpressionStatement Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testA.dart',
+ '''
+ B T1;
+ class B{}''');
+ addTestSource('''
+ import "/testA.dart";
+ class C {a() {C ^}}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_FieldDeclaration_name_typed() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // FieldDeclaration
+ addSource('/testA.dart', 'class A { }');
+ addTestSource('''
+ import "/testA.dart";
+ class C {A ^}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_FieldDeclaration_name_var() async {
+ // SimpleIdentifier VariableDeclaration VariableDeclarationList
+ // FieldDeclaration
+ addSource('/testA.dart', 'class A { }');
+ addTestSource('''
+ import "/testA.dart";
+ class C {var ^}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_FieldFormalParameter_in_non_constructor() async {
+ // SimpleIdentifer FieldFormalParameter FormalParameterList
+ addTestSource('class A {B(this.^foo) {}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 3);
+ assertNoSuggestions();
+ }
+
+ test_ForEachStatement_body_typed() async {
+ // Block ForEachStatement
+ addTestSource('main(args) {for (int foo in bar) {^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertNotSuggested('Object');
+ }
+
+ test_ForEachStatement_body_untyped() async {
+ // Block ForEachStatement
+ addTestSource('main(args) {for (foo in bar) {^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertNotSuggested('Object');
+ }
+
+ test_ForEachStatement_iterable() async {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (int foo in ^) {}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('Object');
+ }
+
+ test_ForEachStatement_loopVariable() async {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ in args) {}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('String');
+ }
+
+ test_ForEachStatement_loopVariable_type() async {
+ // SimpleIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (^ foo in args) {}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertNotSuggested('String');
+ }
+
+ test_ForEachStatement_loopVariable_type2() async {
+ // DeclaredIdentifier ForEachStatement Block
+ addTestSource('main(args) {for (S^ foo in args) {}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('args');
+ assertNotSuggested('foo');
+ assertNotSuggested('String');
+ }
+
+ test_FormalParameterList() async {
+ // FormalParameterList MethodDeclaration
+ addTestSource('''
+ foo() { }
+ void bar() { }
+ class A {a(^) { }}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('foo');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('String');
+ assertNotSuggested('identical');
+ assertNotSuggested('bar');
+ }
+
+ test_ForStatement_body() async {
+ // Block ForStatement
+ addTestSource('main(args) {for (int i; i < 10; ++i) {^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('i');
+ assertNotSuggested('Object');
+ }
+
+ test_ForStatement_condition() async {
+ // SimpleIdentifier ForStatement
+ addTestSource('main() {for (int index = 0; i^)}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('index');
+ }
+
+ test_ForStatement_initializer() async {
+ // SimpleIdentifier ForStatement
+ addTestSource('main() {List a; for (^)}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('Object');
+ assertNotSuggested('int');
+ }
+
+ test_ForStatement_updaters() async {
+ // SimpleIdentifier ForStatement
+ addTestSource('main() {for (int index = 0; index < 10; i^)}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('index');
+ }
+
+ test_ForStatement_updaters_prefix_expression() async {
+ // SimpleIdentifier PrefixExpression ForStatement
+ addTestSource('''
+ void bar() { }
+ main() {for (int index = 0; index < 10; ++i^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('index');
+ assertNotSuggested('main');
+ assertNotSuggested('bar');
+ }
+
+ test_FunctionDeclaration_returnType_afterComment() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ /* */ ^ zoo(z) { } String name;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_FunctionDeclaration_returnType_afterComment2() async {
+ // FunctionDeclaration ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ /** */ ^ zoo(z) { } String name;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_FunctionDeclaration_returnType_afterComment3() async {
+ // FunctionDeclaration ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ /// some dartdoc
+ class C2 { }
+ ^ zoo(z) { } String name;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_FunctionExpression_body_function() async {
+ // Block BlockFunctionBody FunctionExpression
+ addTestSource('''
+ void bar() { }
+ String foo(List args) {x.then((R b) {^}''');
+ await computeSuggestions();
+
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('foo');
+ assertNotSuggested('bar');
+ assertNotSuggested('args');
+ assertNotSuggested('b');
+ assertNotSuggested('Object');
+ }
+
+ test_IfStatement() async {
+ // SimpleIdentifier IfStatement
+ addTestSource('''
+ class A {var b; X _c; foo() {A a; if (true) ^}}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_IfStatement_condition() async {
+ // SimpleIdentifier IfStatement Block BlockFunctionBody
+ addTestSource('''
+ class A {int x; int y() => 0;}
+ main(){var a; if (^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_IfStatement_empty() async {
+ // SimpleIdentifier IfStatement
+ addTestSource('''
+ class A {var b; X _c; foo() {A a; if (^) something}}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_IfStatement_invocation() async {
+ // SimpleIdentifier PrefixIdentifier IfStatement
+ addTestSource('''
+ main() {var a; if (a.^) something}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestMethod('toString', 'Object', 'String');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ assertNotSuggested('==');
+ }
+
+ test_ImportDirective_dart() async {
+ // SimpleStringLiteral ImportDirective
+ addTestSource('''
+ import "dart^";
+ main() {}''');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_IndexExpression() async {
+ // ExpressionStatement Block
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} f[^]}}''');
+ await computeSuggestions();
+ assertNotSuggested('x');
+ assertNotSuggested('f');
+ assertNotSuggested('foo');
+ assertNotSuggested('C');
+ assertNotSuggested('F2');
+ assertNotSuggested('T2');
+ assertNotSuggested('A');
+ assertNotSuggested('F1');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_IndexExpression2() async {
+ // SimpleIdentifier IndexExpression ExpressionStatement Block
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ class B {int x;}
+ class C {foo(){var f; {var x;} f[T^]}}''');
+ await computeSuggestions();
+ // top level results are partially filtered based on first char
+ assertNotSuggested('T2');
+ // TODO (danrubel) getter is being suggested instead of top level var
+ //assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+
+ test_InstanceCreationExpression_imported() async {
+ // SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ class A {A(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ import "dart:async";
+ int T2;
+ F2() { }
+ class B {B(this.x, [String boo]) { } int x;}
+ class C {foo(){var f; {var x;} new ^}}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('Future');
+ assertNotSuggested('A');
+ assertNotSuggested('B');
+ assertNotSuggested('C');
+ assertNotSuggested('f');
+ assertNotSuggested('x');
+ assertNotSuggested('foo');
+ assertNotSuggested('F1');
+ assertNotSuggested('F2');
+ assertNotSuggested('T1');
+ assertNotSuggested('T2');
+ }
+
+ test_InstanceCreationExpression_unimported() async {
+ // SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
+ addSource('/testAB.dart', 'class Foo { }');
+ addTestSource('class C {foo(){new F^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('Future');
+ assertNotSuggested('Foo');
+ }
+
+ test_InterpolationExpression() async {
+ // SimpleIdentifier InterpolationExpression StringInterpolation
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ main() {String name; print("hello \$^");}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ // TODO(danrubel) should return top level var rather than getter
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_InterpolationExpression_block() async {
+ // SimpleIdentifier InterpolationExpression StringInterpolation
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ main() {String name; print("hello \${^}");}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_InterpolationExpression_block2() async {
+ // SimpleIdentifier InterpolationExpression StringInterpolation
+ addTestSource('main() {String name; print("hello \${n^}");}');
+ await computeSuggestions();
+ assertNotSuggested('name');
+ // top level results are partially filtered
+ //assertNotSuggested('Object');
+ }
+
+ test_InterpolationExpression_prefix_selector() async {
+ // SimpleIdentifier PrefixedIdentifier InterpolationExpression
+ addTestSource('main() {String name; print("hello \${name.^}");}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestGetter('length', 'int');
+ assertNotSuggested('name');
+ assertNotSuggested('Object');
+ assertNotSuggested('==');
+ }
+
+ test_InterpolationExpression_prefix_selector2() async {
+ // SimpleIdentifier PrefixedIdentifier InterpolationExpression
+ addTestSource('main() {String name; print("hello \$name.^");}');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_InterpolationExpression_prefix_target() async {
+ // SimpleIdentifier PrefixedIdentifier InterpolationExpression
+ addTestSource('main() {String name; print("hello \${nam^e.length}");}');
+ await computeSuggestions();
+ assertNotSuggested('name');
+ // top level results are partially filtered
+ //assertNotSuggested('Object');
+ assertNotSuggested('length');
+ }
+
+ test_IsExpression() async {
+ // SimpleIdentifier TypeName IsExpression IfStatement
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ foo() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ class Y {Y.c(); Y._d(); z() {}}
+ main() {var x; if (x is ^) { }}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('X');
+ assertNotSuggested('Y');
+ assertNotSuggested('x');
+ assertNotSuggested('main');
+ assertNotSuggested('foo');
+ }
+
+ test_IsExpression_target() async {
+ // IfStatement Block BlockFunctionBody
+ addTestSource('''
+ foo() { }
+ void bar() { }
+ class A {int x; int y() => 0;}
+ main(){var a; if (^ is A)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('foo');
+ assertNotSuggested('bar');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_IsExpression_type() async {
+ // SimpleIdentifier TypeName IsExpression IfStatement
+ addTestSource('''
+ class A {int x; int y() => 0;}
+ main(){var a; if (a is ^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_IsExpression_type_partial() async {
+ // SimpleIdentifier TypeName IsExpression IfStatement
+ addTestSource('''
+ class A {int x; int y() => 0;}
+ main(){var a; if (a is Obj^)}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
+ assertNotSuggested('a');
+ assertNotSuggested('main');
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ }
+
+ test_keyword2() async {
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int newT1;
+ int T1;
+ nowIsIt() { }
+ class X {factory X.c(); factory X._d(); z() {}}''');
+ addTestSource('''
+ import "/testB.dart";
+ String newer() {}
+ var m;
+ main() {new^ X.c();}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 3);
+ expect(replacementLength, 3);
+ assertNotSuggested('c');
+ assertNotSuggested('_d');
+ // Imported suggestion are filtered by 1st character
+ assertNotSuggested('nowIsIt');
+ assertNotSuggested('T1');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ assertNotSuggested('newer');
+ }
+
+ test_Literal_list() async {
+ // ']' ListLiteral ArgumentList MethodInvocation
+ addTestSource('main() {var Some; print([^]);}');
+ await computeSuggestions();
+ assertNotSuggested('Some');
+ assertNotSuggested('String');
+ }
+
+ test_Literal_list2() async {
+ // SimpleIdentifier ListLiteral ArgumentList MethodInvocation
+ addTestSource('main() {var Some; print([S^]);}');
+ await computeSuggestions();
+ assertNotSuggested('Some');
+ assertNotSuggested('String');
+ }
+
+ test_Literal_string() async {
+ // SimpleStringLiteral ExpressionStatement Block
+ addTestSource('class A {a() {"hel^lo"}}');
+ await computeSuggestions();
+ assertNoSuggestions();
+ }
+
+ test_MapLiteralEntry() async {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ foo = {^''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ }
+
+ test_MapLiteralEntry1() async {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ foo = {T^''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('T2');
+ }
+
+ test_MapLiteralEntry2() async {
+ // SimpleIdentifier MapLiteralEntry MapLiteral VariableDeclaration
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 { }
+ foo = {7:T^};''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset - 1);
+ expect(replacementLength, 1);
+ assertNotSuggested('T2');
+ }
+
+ test_MethodDeclaration_body_getters() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {@deprecated X get f => 0; Z a() {^} get _g => 1;}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('f');
+ assertNotSuggested('_g');
+ }
+
+ test_MethodDeclaration_body_static() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addSource(
+ '/testC.dart',
+ '''
+ class C {
+ c1() {}
+ var c2;
+ static c3() {}
+ static var c4;}''');
+ addTestSource('''
+ import "/testC.dart";
+ class B extends C {
+ b1() {}
+ var b2;
+ static b3() {}
+ static var b4;}
+ class A extends B {
+ a1() {}
+ var a2;
+ static a3() {}
+ static var a4;
+ static a() {^}}''');
+ await computeSuggestions();
+ assertNotSuggested('a1');
+ assertNotSuggested('a2');
+ assertNotSuggested('a3');
+ assertNotSuggested('a4');
+ assertNotSuggested('b1');
+ assertNotSuggested('b2');
+ assertNotSuggested('b3');
+ assertNotSuggested('b4');
+ assertNotSuggested('c1');
+ assertNotSuggested('c2');
+ assertNotSuggested('c3');
+ assertNotSuggested('c4');
+ }
+
+ test_MethodDeclaration_members() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {@deprecated X f; Z _a() {^} var _g;}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('_a');
+ assertNotSuggested('f');
+ assertNotSuggested('_g');
+ assertNotSuggested('bool');
+ }
+
+ test_MethodDeclaration_parameters_named() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addTestSource('class A {@deprecated Z a(X x, _, b, {y: boo}) {^}}');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('a');
+ assertNotSuggested('x');
+ assertNotSuggested('y');
+ assertNotSuggested('b');
+ assertNotSuggested('int');
+ assertNotSuggested('_');
+ }
+
+ test_MethodDeclaration_parameters_positional() async {
+ // Block BlockFunctionBody MethodDeclaration
+ addTestSource('''
+ foo() { }
+ void bar() { }
+ class A {Z a(X x, [int y=1]) {^}}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('foo');
+ assertNotSuggested('bar');
+ assertNotSuggested('a');
+ assertNotSuggested('x');
+ assertNotSuggested('y');
+ assertNotSuggested('String');
+ }
+
+ test_MethodDeclaration_returnType() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 {^ zoo(z) { } String name; }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_MethodDeclaration_returnType_afterComment() async {
+ // ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 {/* */ ^ zoo(z) { } String name; }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_MethodDeclaration_returnType_afterComment2() async {
+ // MethodDeclaration ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 {/** */ ^ zoo(z) { } String name; }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_MethodDeclaration_returnType_afterComment3() async {
+ // MethodDeclaration ClassDeclaration CompilationUnit
+ addSource(
+ '/testA.dart',
+ '''
+ int T1;
+ F1() { }
+ typedef D1();
+ class C1 {C1(this.x) { } int x;}''');
+ addTestSource('''
+ import "/testA.dart";
+ int T2;
+ F2() { }
+ typedef D2();
+ class C2 {
+ /// some dartdoc
+ ^ zoo(z) { } String name; }''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('Object');
+ assertNotSuggested('T1');
+ assertNotSuggested('F1');
+ assertNotSuggested('D1');
+ assertNotSuggested('C1');
+ assertNotSuggested('T2');
+ assertNotSuggested('F2');
+ assertNotSuggested('D2');
+ assertNotSuggested('C2');
+ assertNotSuggested('name');
+ }
+
+ test_MethodInvocation_no_semicolon() async {
+ // MethodInvocation ExpressionStatement Block
+ addTestSource('''
+ main() { }
+ class I {X get f => new A();get _g => new A();}
+ class A implements I {
+ var b; X _c;
+ X get d => new A();get _e => new A();
+ // no semicolon between completion point and next statement
+ set s1(I x) {} set _s2(I x) {x.^ m(null);}
+ m(X x) {} I _n(X x) {}}
+ class X{}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertSuggestGetter('f', 'X');
+ assertSuggestGetter('_g', null);
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('d');
+ assertNotSuggested('_e');
+ assertNotSuggested('s1');
+ assertNotSuggested('_s2');
+ assertNotSuggested('m');
+ assertNotSuggested('_n');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('X');
+ assertNotSuggested('Object');
+ assertNotSuggested('==');
+ }
+
+ test_new_instance() async {
+ addTestSource('import "dart:math"; class A {x() {new Random().^}}');
+ await computeSuggestions();
+ assertSuggestMethod('nextBool', 'Random', 'bool');
+ assertSuggestMethod('nextDouble', 'Random', 'double');
+ assertSuggestMethod('nextInt', 'Random', 'int');
+ assertNotSuggested('Random');
+ assertNotSuggested('Object');
+ assertNotSuggested('A');
+ }
+
+ test_parameterName_excludeTypes() async {
+ addTestSource('m(int ^) {}');
+ await computeSuggestions();
+ assertNotSuggested('int');
+ assertNotSuggested('bool');
+ }
+
+ test_partFile_TypeName() async {
+ // SimpleIdentifier TypeName ConstructorName
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addSource(
+ '/testA.dart',
+ '''
+ library libA;
+ import "/testB.dart";
+ part "$testFile";
+ class A { }
+ var m;''');
+ addTestSource('''
+ part of libA;
+ class B { factory B.bar(int x) => null; }
+ main() {new ^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('B.bar');
+ assertNotSuggested('Object');
+ assertNotSuggested('X.c');
+ assertNotSuggested('X._d');
+ assertNotSuggested('A');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_partFile_TypeName2() async {
+ // SimpleIdentifier TypeName ConstructorName
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ int T1;
+ F1() { }
+ class X {X.c(); X._d(); z() {}}''');
+ addSource(
+ '/testA.dart',
+ '''
+ part of libA;
+ class B { }''');
+ addTestSource('''
+ library libA;
+ import "/testB.dart";
+ part "/testA.dart";
+ class A { A({String boo: 'hoo'}) { } }
+ main() {new ^}
+ var m;''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('A');
+ assertNotSuggested('Object');
+ assertNotSuggested('X.c');
+ assertNotSuggested('X._d');
+ assertNotSuggested('B');
+ assertNotSuggested('F1');
+ assertNotSuggested('T1');
+ assertNotSuggested('_d');
+ assertNotSuggested('z');
+ assertNotSuggested('m');
+ }
+
+ test_PrefixedIdentifier_class_const() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement Block
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ class I {
+ static const scI = 'boo';
+ X get f => new A();
+ get _g => new A();}
+ class B implements I {
+ static const int scB = 12;
+ var b; X _c;
+ X get d => new A();get _e => new A();
+ set s1(I x) {} set _s2(I x) {}
+ m(X x) {} I _n(X x) {}}
+ class X{}''');
+ addTestSource('''
+ import "/testB.dart";
+ class A extends B {
+ static const String scA = 'foo';
+ w() { }}
+ main() {A.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ // Suggested by StaticMemberContributor
+ assertNotSuggested('scA');
+ assertNotSuggested('scB');
+ assertNotSuggested('scI');
+ assertNotSuggested('b');
+ assertNotSuggested('_c');
+ assertNotSuggested('d');
+ assertNotSuggested('_e');
+ assertNotSuggested('f');
+ assertNotSuggested('_g');
+ assertNotSuggested('s1');
+ assertNotSuggested('_s2');
+ assertNotSuggested('m');
+ assertNotSuggested('_n');
+ assertNotSuggested('a');
+ assertNotSuggested('A');
+ assertNotSuggested('X');
+ assertNotSuggested('w');
+ assertNotSuggested('Object');
+ assertNotSuggested('==');
+ }
+
+ test_PrefixedIdentifier_class_imported() async {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addSource(
+ '/testB.dart',
+ '''
+ lib B;
+ class I {X get f => new A();get _g => new A();}
+ class A implements I {
+ static const int sc = 12;
+ @deprecated var b; X _c;
+ X get d => new A();get _e => new A();
+ set s1(I x) {} set _s2(I x) {}
+ m(X x) {} I _n(X x) {}}
+ class X{}''');
+ addTestSource('''
+ import "/testB.dart";
+ main() {A a; a.^}''');
+ await computeSuggestions();
+ expect(replacementOffset, completionOffset);
+ expect(replacementLength, 0);
+ assertNotSuggested('sc');
+ assertSuggestField('b', null, isDeprecated: true);