Version 1.9.0-dev.10.7
svn merge -c 44423 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44431 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44432 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44434 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44438 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44441 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44444 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44449 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44456 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44473 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44479 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44481 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44487 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44490 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 44491 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
Merge cl from:
https://codereview.chromium.org/1008443002/
Merge cl from:
https://codereview.chromium.org/1002893002/
Merge patch from:
https://code.google.com/p/dart/issues/detail?id=22823
git-svn-id: http://dart.googlecode.com/svn/trunk@44500 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 8168764..f699bdc 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -393,6 +393,25 @@
}
/**
+ * Return the [AnalysisContext] that contains the given [path].
+ * Return `null` if no context contains the [path].
+ */
+ AnalysisContext getContainingContext(String path) {
+ Folder containingFolder = null;
+ AnalysisContext containingContext = null;
+ folderMap.forEach((Folder folder, AnalysisContext context) {
+ if (folder.isOrContains(path)) {
+ if (containingFolder == null ||
+ containingFolder.path.length < folder.path.length) {
+ containingFolder = folder;
+ containingContext = context;
+ }
+ }
+ });
+ return containingContext;
+ }
+
+ /**
* Return the primary [ContextSourcePair] representing the given [path].
*
* The [AnalysisContext] of this pair will be the context that explicitly
@@ -420,17 +439,7 @@
Resource resource = resourceProvider.getResource(path);
File file = resource is File ? resource : null;
{
- Folder containingFolder = null;
- AnalysisContext containingContext = null;
- folderMap.forEach((Folder folder, AnalysisContext context) {
- if (folder.isOrContains(path)) {
- if (containingFolder == null ||
- containingFolder.path.length < folder.path.length) {
- containingFolder = folder;
- containingContext = context;
- }
- }
- });
+ AnalysisContext containingContext = getContainingContext(path);
if (containingContext != null) {
Source source = file != null
? ContextManager.createSourceInContext(containingContext, file)
@@ -1242,6 +1251,11 @@
if (context != null) {
context.applyChanges(changeSet);
analysisServer.schedulePerformAnalysisOperation(context);
+ List<String> flushedFiles = new List<String>();
+ for (Source source in changeSet.removedSources) {
+ flushedFiles.add(source.fullName);
+ }
+ sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
}
}
@@ -1258,9 +1272,17 @@
@override
void removeContext(Folder folder) {
AnalysisContext context = analysisServer.folderMap.remove(folder);
+
+ // See dartbug.com/22689, the AnalysisContext is computed in
+ // computeFlushedFiles instead of using the referenced context above, this
+ // is an attempt to be careful concerning the referenced issue.
+ List<String> flushedFiles = computeFlushedFiles(folder);
+ sendAnalysisNotificationFlushResults(analysisServer, flushedFiles);
+
if (analysisServer.index != null) {
analysisServer.index.removeContext(context);
}
+ analysisServer.operationQueue.contextRemoved(context);
_onContextsChangedController
.add(new ContextsChangedEvent(removed: [context]));
analysisServer.sendContextAnalysisDoneNotifications(
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index ec26ccb..d715b6b 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -115,6 +115,29 @@
}
/**
+ * Compute the set of files that are being flushed, this is defined as
+ * the set of sources in the removed context (context.sources), that are
+ * orphaned by this context being removed (no other context includes this
+ * file.)
+ */
+ List<String> computeFlushedFiles(Folder folder) {
+ AnalysisContext context = _contexts[folder].context;
+ HashSet<String> flushedFiles = new HashSet<String>();
+ for (Source source in context.sources) {
+ flushedFiles.add(source.fullName);
+ }
+ for (_ContextInfo contextInfo in _contexts.values) {
+ AnalysisContext contextN = contextInfo.context;
+ if (context != contextN) {
+ for (Source source in contextN.sources) {
+ flushedFiles.remove(source.fullName);
+ }
+ }
+ }
+ return flushedFiles.toList(growable:false);
+ }
+
+ /**
* We have finished computing the package map.
*/
void endComputePackageMap() {
diff --git a/pkg/analysis_server/lib/src/operation/operation.dart b/pkg/analysis_server/lib/src/operation/operation.dart
index 1433c90..6c5732d 100644
--- a/pkg/analysis_server/lib/src/operation/operation.dart
+++ b/pkg/analysis_server/lib/src/operation/operation.dart
@@ -5,6 +5,7 @@
library operation;
import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
/**
@@ -13,6 +14,14 @@
*/
abstract class ServerOperation {
/**
+ * The context for this operation. Operations will be automatically
+ * de-queued when their context is destroyed.
+ */
+ final AnalysisContext context;
+
+ ServerOperation(this.context);
+
+ /**
* Returns the priority of this operation.
*/
ServerOperationPriority get priority;
@@ -63,6 +72,8 @@
* before a change is applied to a [Source].
*/
abstract class SourceSensitiveOperation extends ServerOperation {
+ SourceSensitiveOperation(AnalysisContext context) : super(context);
+
/**
* The given [source] is about to be changed.
* Check if this [SourceSensitiveOperation] should be discarded.
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index ecbb97c..243384f 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -36,6 +36,11 @@
void scheduleNotificationOperations(AnalysisServer server, String file,
LineInfo lineInfo, AnalysisContext context, CompilationUnit parsedDartUnit,
CompilationUnit resolvedDartUnit, List<AnalysisError> errors) {
+ // If the file belongs to any analysis root, check whether we're in it now.
+ AnalysisContext containingContext = server.getContainingContext(file);
+ if (containingContext != null && context != containingContext) {
+ return;
+ }
// Dart
CompilationUnit dartUnit =
resolvedDartUnit != null ? resolvedDartUnit : parsedDartUnit;
@@ -43,35 +48,35 @@
if (server.hasAnalysisSubscription(
protocol.AnalysisService.HIGHLIGHTS, file)) {
server.scheduleOperation(
- new _DartHighlightsOperation(file, resolvedDartUnit));
+ new _DartHighlightsOperation(context, file, resolvedDartUnit));
}
if (server.hasAnalysisSubscription(
protocol.AnalysisService.NAVIGATION, file)) {
server.scheduleOperation(
- new _DartNavigationOperation(file, resolvedDartUnit));
+ new _DartNavigationOperation(context, file, resolvedDartUnit));
}
if (server.hasAnalysisSubscription(
protocol.AnalysisService.OCCURRENCES, file)) {
server.scheduleOperation(
- new _DartOccurrencesOperation(file, resolvedDartUnit));
+ new _DartOccurrencesOperation(context, file, resolvedDartUnit));
}
if (server.hasAnalysisSubscription(
protocol.AnalysisService.OVERRIDES, file)) {
server.scheduleOperation(
- new _DartOverridesOperation(file, resolvedDartUnit));
+ new _DartOverridesOperation(context, file, resolvedDartUnit));
}
}
if (dartUnit != null) {
if (server.hasAnalysisSubscription(
protocol.AnalysisService.OUTLINE, file)) {
server.scheduleOperation(
- new _DartOutlineOperation(file, lineInfo, dartUnit));
+ new _DartOutlineOperation(context, file, lineInfo, dartUnit));
}
}
// errors
if (server.shouldSendErrorsNotificationFor(file)) {
server.scheduleOperation(
- new _NotificationErrorsOperation(file, lineInfo, errors));
+ new _NotificationErrorsOperation(context, file, lineInfo, errors));
}
}
@@ -88,6 +93,16 @@
});
}
+void sendAnalysisNotificationFlushResults(
+ AnalysisServer server, List<String> files) {
+ _sendNotification(server, () {
+ if (files != null && files.isNotEmpty) {
+ var params = new protocol.AnalysisFlushResultsParams(files);
+ server.sendNotification(params.toNotification());
+ }
+ });
+}
+
void sendAnalysisNotificationHighlights(
AnalysisServer server, String file, CompilationUnit dartUnit) {
_sendNotification(server, () {
@@ -156,10 +171,10 @@
static const int IDLE_CACHE_SIZE = AnalysisOptionsImpl.DEFAULT_CACHE_SIZE;
static const int WORKING_CACHE_SIZE = 512;
- final AnalysisContext context;
final bool isContinue;
- PerformAnalysisOperation(this.context, this.isContinue);
+ PerformAnalysisOperation(AnalysisContext context, this.isContinue)
+ : super(context);
@override
ServerOperationPriority get priority {
@@ -266,8 +281,9 @@
}
class _DartHighlightsOperation extends _DartNotificationOperation {
- _DartHighlightsOperation(String file, CompilationUnit unit)
- : super(file, unit);
+ _DartHighlightsOperation(
+ AnalysisContext context, String file, CompilationUnit unit)
+ : super(context, file, unit);
@override
void perform(AnalysisServer server) {
@@ -276,10 +292,10 @@
}
class _DartIndexOperation extends _SingleFileOperation {
- final AnalysisContext context;
final CompilationUnit unit;
- _DartIndexOperation(this.context, String file, this.unit) : super(file);
+ _DartIndexOperation(AnalysisContext context, String file, this.unit)
+ : super(context, file);
@override
ServerOperationPriority get priority {
@@ -296,8 +312,9 @@
}
class _DartNavigationOperation extends _DartNotificationOperation {
- _DartNavigationOperation(String file, CompilationUnit unit)
- : super(file, unit);
+ _DartNavigationOperation(
+ AnalysisContext context, String file, CompilationUnit unit)
+ : super(context, file, unit);
@override
void perform(AnalysisServer server) {
@@ -308,7 +325,8 @@
abstract class _DartNotificationOperation extends _SingleFileOperation {
final CompilationUnit unit;
- _DartNotificationOperation(String file, this.unit) : super(file);
+ _DartNotificationOperation(AnalysisContext context, String file, this.unit)
+ : super(context, file);
@override
ServerOperationPriority get priority {
@@ -317,8 +335,9 @@
}
class _DartOccurrencesOperation extends _DartNotificationOperation {
- _DartOccurrencesOperation(String file, CompilationUnit unit)
- : super(file, unit);
+ _DartOccurrencesOperation(
+ AnalysisContext context, String file, CompilationUnit unit)
+ : super(context, file, unit);
@override
void perform(AnalysisServer server) {
@@ -329,8 +348,9 @@
class _DartOutlineOperation extends _DartNotificationOperation {
final LineInfo lineInfo;
- _DartOutlineOperation(String file, this.lineInfo, CompilationUnit unit)
- : super(file, unit);
+ _DartOutlineOperation(
+ AnalysisContext context, String file, this.lineInfo, CompilationUnit unit)
+ : super(context, file, unit);
@override
void perform(AnalysisServer server) {
@@ -339,8 +359,9 @@
}
class _DartOverridesOperation extends _DartNotificationOperation {
- _DartOverridesOperation(String file, CompilationUnit unit)
- : super(file, unit);
+ _DartOverridesOperation(
+ AnalysisContext context, String file, CompilationUnit unit)
+ : super(context, file, unit);
@override
void perform(AnalysisServer server) {
@@ -349,10 +370,10 @@
}
class _HtmlIndexOperation extends _SingleFileOperation {
- final AnalysisContext context;
final HtmlUnit unit;
- _HtmlIndexOperation(this.context, String file, this.unit) : super(file);
+ _HtmlIndexOperation(AnalysisContext context, String file, this.unit)
+ : super(context, file);
@override
ServerOperationPriority get priority {
@@ -370,8 +391,9 @@
final LineInfo lineInfo;
final List<AnalysisError> errors;
- _NotificationErrorsOperation(String file, this.lineInfo, this.errors)
- : super(file);
+ _NotificationErrorsOperation(
+ AnalysisContext context, String file, this.lineInfo, this.errors)
+ : super(context, file);
@override
ServerOperationPriority get priority {
@@ -387,7 +409,7 @@
abstract class _SingleFileOperation extends SourceSensitiveOperation {
final String file;
- _SingleFileOperation(this.file);
+ _SingleFileOperation(AnalysisContext context, this.file) : super(context);
@override
bool shouldBeDiscardedOnSourceChange(Source source) {
diff --git a/pkg/analysis_server/lib/src/operation/operation_queue.dart b/pkg/analysis_server/lib/src/operation/operation_queue.dart
index 7ea8257..ced4a8c 100644
--- a/pkg/analysis_server/lib/src/operation/operation_queue.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_queue.dart
@@ -8,6 +8,7 @@
import 'package:analysis_server/src/analysis_server.dart';
import 'package:analysis_server/src/operation/operation.dart';
+import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
/**
@@ -51,6 +52,16 @@
}
/**
+ * The given [context] has been removed, so all pending operations that refer
+ * to it should be removed from the queue.
+ */
+ void contextRemoved(AnalysisContext context) {
+ for (Queue<ServerOperation> queue in _queues) {
+ queue.removeWhere((operation) => operation.context == context);
+ }
+ }
+
+ /**
* Return the next operation to perform, or `null` if the queue is empty.
* This method does not change the queue.
*/
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
index a5e4418..55b342a 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_computer.dart
@@ -179,7 +179,7 @@
completion.toString(), completion.length, 0, false, false);
suggestion.parameterNames = paramNames;
suggestion.parameterTypes = paramTypes;
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
}
String _getParamType(FormalParameter param) {
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 ca9c75a..17127f7 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
@@ -198,6 +198,11 @@
void _addDartCoreSuggestions() {
Source coreUri = context.sourceFactory.forUri('dart:core');
LibraryElement coreLib = context.getLibraryElement(coreUri);
+ if (coreLib == null) {
+ // If the core library has not been analyzed yet, then we cannot add any
+ // suggestions from it.
+ return;
+ }
Namespace coreNamespace =
new NamespaceBuilder().createPublicNamespaceForLibrary(coreLib);
coreNamespace.definedNames.forEach((String name, Element elem) {
@@ -272,10 +277,11 @@
*/
void _addNonImportedElementSuggestions(
List<SearchMatch> matches, Set<LibraryElement> excludedLibs) {
+ AnalysisContext sdkContext = context.sourceFactory.dartSdk.context;
matches.forEach((SearchMatch match) {
if (match.kind == MatchKind.DECLARATION) {
Element element = match.element;
- if (element.context == context &&
+ if ((element.context == context || element.context == sdkContext) &&
element.isPublic &&
!excludedLibs.contains(element.library) &&
!_importedCompletions.contains(element.displayName)) {
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 15f26b2..0f77b19 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
@@ -78,11 +78,13 @@
: super(context, source) {
if (computers == null) {
computers = [
- new KeywordComputer(),
+ // LocalComputer before ImportedComputer
+ // because local suggestions take precedence
new LocalComputer(),
+ new ImportedComputer(),
+ new KeywordComputer(),
new ArgListComputer(),
new CombinatorComputer(),
- new ImportedComputer(),
new InvocationComputer()
];
}
@@ -315,7 +317,12 @@
/**
* The list of suggestions to be sent to the client.
*/
- final List<CompletionSuggestion> suggestions = <CompletionSuggestion>[];
+ final List<CompletionSuggestion> _suggestions = <CompletionSuggestion>[];
+
+ /**
+ * The set of completions used to prevent duplicates
+ */
+ final Set<String> _completions = new Set<String>();
DartCompletionRequest(this.context, this.searchEngine, this.source,
int offset, this.cache, CompletionPerformance performance)
@@ -342,17 +349,32 @@
}
/**
+ * The list of suggestions to be sent to the client.
+ */
+ Iterable<CompletionSuggestion> get suggestions => _suggestions;
+
+ /**
+ * Add the given suggestion to the list that is returned to the client as long
+ * as a suggestion with an identical completion has not already been added.
+ */
+ void addSuggestion(CompletionSuggestion suggestion) {
+ if (_completions.add(suggestion.completion)) {
+ _suggestions.add(suggestion);
+ }
+ }
+
+ /**
* Convert all [CompletionSuggestionKind.INVOCATION] suggestions
* to [CompletionSuggestionKind.IDENTIFIER] suggestions.
*/
void convertInvocationsToIdentifiers() {
- for (int index = suggestions.length - 1; index >= 0; --index) {
- CompletionSuggestion suggestion = suggestions[index];
+ for (int index = _suggestions.length - 1; index >= 0; --index) {
+ CompletionSuggestion suggestion = _suggestions[index];
if (suggestion.kind == CompletionSuggestionKind.INVOCATION) {
// Create a copy rather than just modifying the existing suggestion
// because [DartCompletionCache] may be caching that suggestion
// for future completion requests
- suggestions[index] = new CompletionSuggestion(
+ _suggestions[index] = new CompletionSuggestion(
CompletionSuggestionKind.IDENTIFIER, suggestion.relevance,
suggestion.completion, suggestion.selectionOffset,
suggestion.selectionLength, suggestion.isDeprecated,
diff --git a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
index 5a06b21..2031557 100644
--- a/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/imported_computer.dart
@@ -170,11 +170,11 @@
unfiltered.forEach((CompletionSuggestion suggestion) {
if (filterText.length > 0) {
if (suggestion.completion.startsWith(filterText)) {
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
}
} else {
if (suggestion.relevance != DART_RELEVANCE_LOW) {
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
}
}
});
diff --git a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
index 494a57d..9d154ec 100644
--- a/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/invocation_computer.dart
@@ -64,10 +64,12 @@
} else if (node is PropertyAccess) {
node = (node as PropertyAccess).realTarget;
}
- if (node is Identifier && node.bestElement is ClassElement) {
- node.bestElement
- .accept(new _PrefixedIdentifierSuggestionBuilder(request));
- return new Future.value(true);
+ 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) {
InterfaceTypeSuggestionBuilder.suggestionsFor(request, node.bestType);
@@ -328,7 +330,6 @@
}
}
}
- ;
return new Future.value(modified);
}
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
index db65d77..36d403b 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
@@ -219,7 +219,7 @@
void _addSuggestion(Keyword keyword,
[int relevance = DART_RELEVANCE_DEFAULT]) {
String completion = keyword.syntax;
- request.suggestions.add(new CompletionSuggestion(
+ request.addSuggestion(new CompletionSuggestion(
CompletionSuggestionKind.KEYWORD,
relevance, completion, completion.length, 0, false, false));
}
diff --git a/pkg/analysis_server/lib/src/services/completion/local_computer.dart b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
index 4f6b138..028b116 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_computer.dart
@@ -272,7 +272,7 @@
parameterTypes: parameterTypes,
requiredParameterCount: requiredParameterCount,
hasNamedParameters: hasNamedParameters);
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
return suggestion;
}
@@ -402,7 +402,7 @@
CompletionSuggestion suggestion = new CompletionSuggestion(
CompletionSuggestionKind.IDENTIFIER, DART_RELEVANCE_DEFAULT,
completion, completion.length, 0, false, false);
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
return suggestion;
}
}
@@ -681,7 +681,7 @@
}
}
}
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
return suggestion;
}
}
diff --git a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
index 31d59fc..ef36304 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_declaration_visitor.dart
@@ -144,6 +144,12 @@
}
@override
+ visitConstructorDeclaration(ConstructorDeclaration node) {
+ _visitParamList(node.parameters);
+ visitNode(node);
+ }
+
+ @override
void visitForEachStatement(ForEachStatement node) {
SimpleIdentifier id;
TypeName type;
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index cba5695..72c6e22 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -139,6 +139,22 @@
@override
void visitBinaryExpression(BinaryExpression node) {
if (identical(entity, node.rightOperand)) {
+ // An empty type argument list is parsed as a binary expression
+ // `C<>` is parsed as `C < `
+ Object entity = this.entity;
+ if (entity is SimpleIdentifier && entity.isSynthetic) {
+ Token operator = node.operator;
+ if (operator != null && operator.lexeme == '<') {
+ Token next = entity.token.next;
+ if (next is StringToken && next.lexeme.length == 0) {
+ next = next.next;
+ }
+ if (next != null && next.lexeme == '>') {
+ optype.includeTypeNameSuggestions = true;
+ return;
+ }
+ }
+ }
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
}
@@ -384,7 +400,7 @@
}
@override
- void visitListLiteral(ListLiteral node) {
+ void visitMapLiteralEntry(MapLiteralEntry node) {
optype.includeReturnValueSuggestions = true;
optype.includeTypeNameSuggestions = true;
}
@@ -496,6 +512,23 @@
}
@override
+ void visitTypeArgumentList(TypeArgumentList node) {
+ NodeList<TypeName> arguments = node.arguments;
+ for (TypeName typeName in arguments) {
+ if (identical(entity, typeName)) {
+ optype.includeTypeNameSuggestions = true;
+ break;
+ }
+ }
+ }
+
+ @override
+ void visitTypedLiteral(TypedLiteral node) {
+ optype.includeReturnValueSuggestions = true;
+ optype.includeTypeNameSuggestions = true;
+ }
+
+ @override
void visitTypeName(TypeName node) {
// The entity won't be the first child entity (node.name), since
// CompletionTarget would have chosen an edge higher in the parse tree. So
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 c226403..e882474 100644
--- a/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/suggestion_builder.dart
@@ -165,11 +165,6 @@
abstract class ElementSuggestionBuilder {
/**
- * Internal collection of completions to prevent duplicate completions.
- */
- final Set<String> _completions = new Set<String>();
-
- /**
* Return the kind of suggestions that should be built.
*/
CompletionSuggestionKind get kind;
@@ -196,15 +191,13 @@
}
}
String completion = element.displayName;
- if (completion == null ||
- completion.length <= 0 ||
- !_completions.add(completion)) {
+ if (completion == null || completion.length <= 0) {
return;
}
CompletionSuggestion suggestion =
createSuggestion(element, kind: kind, relevance: relevance);
if (suggestion != null) {
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
}
}
}
@@ -307,7 +300,7 @@
}
CompletionSuggestion suggestion = createSuggestion(element, kind: kind);
if (suggestion != null) {
- request.suggestions.add(suggestion);
+ request.addSuggestion(suggestion);
}
}
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index bd78f9f..5913930 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -191,6 +191,34 @@
});
}
+ test_getAnalysisContext_nested() {
+ String dir1Path = '/dir1';
+ String dir2Path = dir1Path + '/dir2';
+ String filePath = dir2Path + '/file.dart';
+ Folder dir1 = resourceProvider.newFolder(dir1Path);
+ Folder dir2 = resourceProvider.newFolder(dir2Path);
+ resourceProvider.newFile(filePath, 'library lib;');
+
+ AnalysisContext context1 = AnalysisEngine.instance.createAnalysisContext();
+ AnalysisContext context2 = AnalysisEngine.instance.createAnalysisContext();
+ server.folderMap[dir1] = context1;
+ server.folderMap[dir2] = context2;
+
+ expect(server.getAnalysisContext(filePath), context2);
+ }
+
+ test_getAnalysisContext_simple() {
+ String dirPath = '/dir';
+ String filePath = dirPath + '/file.dart';
+ Folder dir = resourceProvider.newFolder(dirPath);
+ resourceProvider.newFile(filePath, 'library lib;');
+
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ server.folderMap[dir] = context;
+
+ expect(server.getAnalysisContext(filePath), context);
+ }
+
Future test_getAnalysisContextForSource() {
// Subscribe to STATUS so we'll know when analysis is done.
server.serverServices = [ServerService.STATUS].toSet();
@@ -283,6 +311,72 @@
expect(source.fullName, filePath);
}
+ test_operationsRemovedOnContextDisposal() async {
+ resourceProvider.newFolder('/foo');
+ resourceProvider.newFile('/foo/baz.dart', 'library lib;');
+ resourceProvider.newFolder('/bar');
+ resourceProvider.newFile('/bar/baz.dart', 'library lib;');
+ server.setAnalysisRoots('0', ['/foo', '/bar'], [], {});
+ await pumpEventQueue();
+ AnalysisContext contextFoo = server.getAnalysisContext('/foo/baz.dart');
+ AnalysisContext contextBar = server.getAnalysisContext('/bar/baz.dart');
+ _MockServerOperation operationFoo = new _MockServerOperation(contextFoo);
+ _MockServerOperation operationBar = new _MockServerOperation(contextBar);
+ server.scheduleOperation(operationFoo);
+ server.scheduleOperation(operationBar);
+ server.setAnalysisRoots('1', ['/foo'], [], {});
+ await pumpEventQueue();
+ expect(operationFoo.isComplete, isTrue);
+ expect(operationBar.isComplete, isFalse);
+ }
+
+ /**
+ * Test that having multiple analysis contexts analyze the same file doesn't
+ * cause that file to receive duplicate notifications when it's modified.
+ */
+ Future test_no_duplicate_notifications() async {
+ // Subscribe to STATUS so we'll know when analysis is done.
+ server.serverServices = [ServerService.STATUS].toSet();
+ resourceProvider.newFolder('/foo');
+ resourceProvider.newFolder('/bar');
+ resourceProvider.newFile('/foo/foo.dart', 'import "../bar/bar.dart";');
+ File bar = resourceProvider.newFile('/bar/bar.dart', 'library bar;');
+ server.setAnalysisRoots('0', ['/foo', '/bar'], [], {});
+ Map<AnalysisService, Set<String>> subscriptions =
+ <AnalysisService, Set<String>>{};
+ for (AnalysisService service in AnalysisService.VALUES) {
+ subscriptions[service] = <String>[bar.path].toSet();
+ }
+ server.setAnalysisSubscriptions(subscriptions);
+ await pumpEventQueue(100);
+ expect(server.statusAnalyzing, isFalse);
+ channel.notificationsReceived.clear();
+ server.updateContent(
+ '0', {bar.path: new AddContentOverlay('library bar; void f() {}')});
+ await pumpEventQueue(100);
+ expect(server.statusAnalyzing, isFalse);
+ expect(channel.notificationsReceived, isNotEmpty);
+ Set<String> notificationTypesReceived = new Set<String>();
+ for (Notification notification in channel.notificationsReceived) {
+ String notificationType = notification.event;
+ switch (notificationType) {
+ case 'server.status':
+ case 'analysis.errors':
+ // It's normal for these notifications to be sent multiple times.
+ break;
+ case 'analysis.outline':
+ // It's normal for this notification to be sent twice.
+ // TODO(paulberry): why?
+ break;
+ default:
+ if (!notificationTypesReceived.add(notificationType)) {
+ fail('Notification type $notificationType received more than once');
+ }
+ break;
+ }
+ }
+ }
+
Future test_prioritySourcesChangedEvent() {
resourceProvider.newFolder('/foo');
@@ -403,3 +497,22 @@
return null;
}
}
+
+/**
+ * A [ServerOperation] that does nothing but keep track of whether or not it
+ * has been performed.
+ */
+class _MockServerOperation implements ServerOperation {
+ final AnalysisContext context;
+ bool isComplete = false;
+
+ _MockServerOperation(this.context);
+
+ @override
+ ServerOperationPriority get priority => ServerOperationPriority.ANALYSIS;
+
+ @override
+ void perform(AnalysisServer server) {
+ isComplete = true;
+ }
+}
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index eec4109..cc43193 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -71,7 +71,7 @@
buildTests('testCommentSnippets007', '''
class C {mth(Map x, !1) {}mtf(!2, Map x) {}m() {for (in!3t i=0; i<5; i++); A!4 x;}}class int{}class Arrays{}''',
- <String>["1+bool", "2+bool", "3+int", "4+Arrays"], failingTests: '3');
+ <String>["1+bool", "2+bool", "3+int", "4+Arrays"]);
buildTests('testCommentSnippets008', '''
class Date{}final num M = Dat!1''', <String>["1+Date"]);
@@ -118,14 +118,8 @@
class F {var x = !1false;}''', <String>["1+true"], failingTests: '1');
buildTests('testCommentSnippets018', '''
-class Map{}class Arrays{}class C{ m(!1){} n(!2 x, q)''', <String>[
- "1+Map",
- "1-void",
- "1-null",
- "2+Arrays",
- "2-void",
- "2-null"
- ], failingTests: '1');
+class Map{}class Arrays{}class C{ m(!1){} n(!2 x, q)''',
+ <String>["1+Map", "1-void", "1-null", "2+Arrays", "2-void", "2-null"]);
buildTests('testCommentSnippets019', '''
class A{m(){Object x;x.!1/**/clear()''', <String>["1+toString"]);
@@ -136,13 +130,13 @@
buildTests('testCommentSnippets021', '''
class Map{}class tst {var newt;void newf(){}test() {var newz;new !1/**/;}}''',
- <String>["1+Map", "1-newt"], failingTests: '1');
+ <String>["1+Map", "1-newt"]);
buildTests('testCommentSnippets022', '''
-class Map{}class F{m(){new !1;}}''', <String>["1+Map"], failingTests: '1');
+class Map{}class F{m(){new !1;}}''', <String>["1+Map"]);
buildTests('testCommentSnippets022a', '''
-class Map{}class F{m(){new !1''', <String>["1+Map"], failingTests: '1');
+class Map{}class F{m(){new !1''', <String>["1+Map"]);
buildTests('testCommentSnippets022b', '''
class Map{factory Map.qq(){return null;}}class F{m(){new Map.!1qq();}}''',
@@ -157,18 +151,18 @@
buildTests('testCommentSnippets025', '''
class q {num m() {var q; num x=!1 q!3 + !2/**/;}}''',
- <String>["1+q", "2+q", "3+q"], failingTests: '123');
+ <String>["1+q", "2+q", "3+q"]);
buildTests('testCommentSnippets026', '''
-class List{}class a implements !1{}''', <String>["1+List"], failingTests: '1');
+class List{}class a implements !1{}''', <String>["1+List"]);
buildTests('testCommentSnippets027', '''
class String{}class List{}class test <X extends !1String!2> {}''',
- <String>["1+List", "2+String", "2-List"], failingTests: '12');
+ <String>["1+List", "2+String", "2-List"]);
buildTests('testCommentSnippets028', '''
class String{}class List{}class DateTime{}typedef T Y<T extends !1>(List input);''',
- <String>["1+DateTime", "1+String"], failingTests: '1');
+ <String>["1+DateTime", "1+String"]);
buildTests('testCommentSnippets029', '''
interface A<X> default B<X extends !1List!2> {}''',
@@ -198,7 +192,7 @@
<String>["1+length", "2+clear"]);
buildTests('testCommentSnippets036', '''
-class List{}t3() {var x=new List!1}''', <String>["1+List"], failingTests: '1');
+class List{}t3() {var x=new List!1}''', <String>["1+List"]);
buildTests('testCommentSnippets037', '''
class List{factory List.from(){}}t3() {var x=new List.!1}''',
@@ -233,7 +227,7 @@
buildTests('testCommentSnippets044', '''
class List{}class XXX {XXX.fisk();}main() {main(); new !1}}''',
- <String>["1+List", "1+XXX.fisk"], failingTests: '1');
+ <String>["1+List", "1+XXX.fisk"]);
buildTests('testCommentSnippets047', '''
f(){int x;int y=!1;}''', <String>["1+x"]);
@@ -599,11 +593,11 @@
buildTests('testCommentSnippets076', '''
class Map<K,V>{}class List<E>{}class int{}main() {var m=new Map<Lis!1t<Map<int,in!2t>>,List<!3int>>();}''',
- <String>["1+List", "2+int", "3+int"], failingTests: '123');
+ <String>["1+List", "2+int", "3+int"]);
buildTests('testCommentSnippets076a', '''
class Map<K,V>{}class List<E>{}class int{}main() {var m=new Map<Lis!1t<Map<int,in!2t>>,List<!3>>();}''',
- <String>["1+List", "2+int", "3+int"], failingTests: '123');
+ <String>["1+List", "2+int", "3+int"]);
buildTests('testCommentSnippets077', '''
class FileMode {
@@ -903,8 +897,7 @@
*/
A.named(aaa, bbb) {}
methodA() {}
-}''', <String>["1+aaa", "1-bbb", "2+int", "2-double", "3+methodA"],
- failingTests: '1');
+}''', <String>["1+aaa", "1-bbb", "2+int", "2-double", "3+methodA"]);
buildTests('testCompletion_dartDoc_reference_forFunction', '''
/**
@@ -1028,7 +1021,7 @@
buildTests('testCompletion_forStmt_vars', '''
class int{}class Foo { mth() { for (in!1t i = 0; i!2 < 5; i!3++); }}''',
- <String>["1+int", "2+i", "3+i"], failingTests: '1');
+ <String>["1+int", "2+i", "3+i"]);
buildTests('testCompletion_function', '''
class Foo { int boo = 7; mth() { PNGS.sort((String a, Str!1) => a.compareTo(b)); }}''',
@@ -1292,15 +1285,15 @@
buildTests('testCompletion_newMemberType1', '''
class Collection{}class List extends Collection{}class Foo { !1 }''',
- <String>["1+Collection", "1+List"], failingTests: '1');
+ <String>["1+Collection", "1+List"]);
buildTests('testCompletion_newMemberType2', '''
class Collection{}class List extends Collection{}class Foo {!1}''',
- <String>["1+Collection", "1+List"], failingTests: '1');
+ <String>["1+Collection", "1+List"]);
buildTests('testCompletion_newMemberType3', '''
class Collection{}class List extends Collection{}class Foo {L!1}''',
- <String>["1-Collection", "1+List"], failingTests: '1');
+ <String>["1-Collection", "1+List"]);
buildTests('testCompletion_newMemberType4', '''
class Collection{}class List extends Collection{}class Foo {C!1}''',
@@ -1416,7 +1409,7 @@
buildTests('testCompletion_staticField1', '''
class num{}class Sunflower {static final n!2um MAX_D = 300;nu!3m xc, yc;Sun!4flower() {x!Xc = y!Yc = MA!1 }}''',
<String>["1+MAX_D", "X+xc", "Y+yc", "2+num", "3+num", "4+Sunflower"],
- failingTests: '23');
+ failingTests: '2');
buildTests('testCompletion_super_superType', '''
class A {
@@ -1501,7 +1494,7 @@
buildTests('testCompletion_topLevelField_init2', '''
class DateTime{static var JUN;}final num M = Dat!1eTime.JUN;''',
- <String>["1+DateTime", "1-void"], failingTests: '1');
+ <String>["1+DateTime", "1-void"]);
buildTests('testCompletion_while', '''
class Foo { int boo = 7; mth() { while (b!1) {} }}''', <String>["1+boo"]);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 20f6a41..b594773 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -421,7 +421,7 @@
}
test_locals() {
- addTestFile('class A {var a; x() {var b;^}}');
+ addTestFile('class A {var a; x() {var b;^}} class DateTime { }');
return getSuggestions().then((_) {
expect(replacementOffset, equals(completionOffset));
expect(replacementLength, equals(0));
@@ -432,6 +432,21 @@
DART_RELEVANCE_LOCAL_VARIABLE);
assertHasResult(CompletionSuggestionKind.INVOCATION, 'x',
DART_RELEVANCE_LOCAL_METHOD);
+ assertHasResult(CompletionSuggestionKind.INVOCATION, 'DateTime');
+ });
+ }
+
+ test_overrides() {
+ addFile('/libA.dart', 'class A {m() {}}');
+ addTestFile('''
+import '/libA.dart';
+class B extends A {m() {^}}
+''');
+ return getSuggestions().then((_) {
+ expect(replacementOffset, equals(completionOffset));
+ expect(replacementLength, equals(0));
+ assertHasResult(CompletionSuggestionKind.INVOCATION, 'm',
+ DART_RELEVANCE_LOCAL_METHOD);
});
}
diff --git a/pkg/analysis_server/test/mock_sdk.dart b/pkg/analysis_server/test/mock_sdk.dart
index 504ecd9..920cb32 100644
--- a/pkg/analysis_server/test/mock_sdk.dart
+++ b/pkg/analysis_server/test/mock_sdk.dart
@@ -107,6 +107,7 @@
import 'dart:math';
class Future<T> {
+ factory Future(computation()) => null;
factory Future.delayed(Duration duration, [T computation()]) => null;
factory Future.value([value]) => null;
static Future wait(List<Future> futures) => null;
diff --git a/pkg/analysis_server/test/operation/operation_queue_test.dart b/pkg/analysis_server/test/operation/operation_queue_test.dart
index 09a8afd..de5e795 100644
--- a/pkg/analysis_server/test/operation/operation_queue_test.dart
+++ b/pkg/analysis_server/test/operation/operation_queue_test.dart
@@ -61,6 +61,30 @@
expect(queue.isEmpty, true);
}
+ void test_contextRemoved() {
+ var contextA = new AnalysisContextMock();
+ var contextB = new AnalysisContextMock();
+ var opA1 = new _ServerOperationMock(contextA);
+ var opA2 = new _ServerOperationMock(contextA);
+ var opB1 = new _ServerOperationMock(contextB);
+ var opB2 = new _ServerOperationMock(contextB);
+ when(opA1.priority)
+ .thenReturn(ServerOperationPriority.ANALYSIS_NOTIFICATION);
+ when(opA2.priority)
+ .thenReturn(ServerOperationPriority.ANALYSIS_NOTIFICATION);
+ when(opB1.priority)
+ .thenReturn(ServerOperationPriority.ANALYSIS_NOTIFICATION);
+ when(opB2.priority)
+ .thenReturn(ServerOperationPriority.ANALYSIS_NOTIFICATION);
+ queue.add(opA1);
+ queue.add(opB1);
+ queue.add(opA2);
+ queue.add(opB2);
+ queue.contextRemoved(contextA);
+ expect(queue.take(), same(opB1));
+ expect(queue.take(), same(opB2));
+ }
+
void test_isEmpty_false() {
var operation = mockOperation(ServerOperationPriority.ANALYSIS);
queue.add(operation);
@@ -148,6 +172,10 @@
}
class _ServerOperationMock extends TypedMock implements ServerOperation {
+ final AnalysisContext context;
+
+ _ServerOperationMock([this.context]);
+
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 6536782..37afa8f 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -181,7 +181,7 @@
this.request = request;
fastCount++;
if (fastSuggestion != null) {
- request.suggestions.add(fastSuggestion);
+ request.addSuggestion(fastSuggestion);
}
return fastSuggestion != null;
}
@@ -191,7 +191,7 @@
this.request = request;
fullCount++;
if (fullSuggestion != null) {
- request.suggestions.add(fullSuggestion);
+ request.addSuggestion(fullSuggestion);
}
return new Future.value(fullSuggestion != null);
}
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index e416cb4..16983af 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -39,9 +39,10 @@
void assertTarget(entityText, nodeText,
{int argIndex: null, bool isFunctionalArgument: false}) {
void assertCommon() {
- expect(target.entity.toString(), entityText);
- expect(target.containingNode.toString(), nodeText);
- expect(target.argIndex, argIndex);
+ expect(target.entity.toString(), entityText, reason: 'entity');
+ expect(target.containingNode.toString(), nodeText,
+ reason: 'containingNode');
+ expect(target.argIndex, argIndex, reason: 'argIndex');
}
// Assert with parsed unit
assertCommon();
@@ -300,6 +301,24 @@
assertTarget('new C();', '{var f; {var x;} new C();}');
}
+ test_MapLiteralEntry() {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {^');
+ assertTarget(' : ', '{ : }');
+ }
+
+ test_MapLiteralEntry1() {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {T^');
+ assertTarget('T : ', '{T : }');
+ }
+
+ test_MapLiteralEntry2() {
+ // SimpleIdentifier MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {7:T^};');
+ assertTarget('T', '7 : T');
+ }
+
test_MethodDeclaration_inLineComment() {
// Comment ClassDeclaration CompilationUnit
addTestSource('''
@@ -455,6 +474,18 @@
assertTarget('zoo', 'zoo(z) {}');
}
+ test_TypeArgumentList() {
+ // SimpleIdentifier BinaryExpression ExpressionStatement
+ addTestSource('main() { C<^> c; }');
+ assertTarget('', 'C < ');
+ }
+
+ test_TypeArgumentList2() {
+ // TypeName TypeArgumentList TypeName
+ addTestSource('main() { C<C^> c; }');
+ assertTarget('C', '<C>');
+ }
+
test_VariableDeclaration_lhs_identifier_after() {
// VariableDeclaration VariableDeclarationList
addTestSource('main() {int b^ = 1;}');
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 edafc5f..40d31a8 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -201,8 +201,9 @@
return cs;
}
- CompletionSuggestion assertSuggestConstructor(String name) {
- CompletionSuggestion cs = assertSuggest(name);
+ CompletionSuggestion assertSuggestConstructor(String name,
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
+ CompletionSuggestion cs = assertSuggest(name, relevance: relevance);
protocol.Element element = cs.element;
expect(element, isNotNull);
expect(element.kind, equals(protocol.ElementKind.CONSTRUCTOR));
@@ -570,7 +571,8 @@
}
}
- CompletionSuggestion assertSuggestImportedConstructor(String name) {
+ CompletionSuggestion assertSuggestImportedConstructor(String name,
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
return assertNotSuggested(name);
}
@@ -826,8 +828,8 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- assertSuggestLocalFunction(
- 'bar', 'String', kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestLocalFunction('bar', 'String',
+ kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('hasLength', 'bool',
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('identical', 'bool',
@@ -862,8 +864,8 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- assertSuggestLocalFunction(
- 'bar', 'String', kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestLocalFunction('bar', 'String',
+ kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('hasLength', 'bool',
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('identical', 'bool',
@@ -953,8 +955,8 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- assertSuggestLocalFunction(
- 'bar', 'String', kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestLocalFunction('bar', 'String',
+ kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('hasLength', 'bool',
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('identical', 'bool',
@@ -987,8 +989,8 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
assertNoSuggestions(kind: CompletionSuggestionKind.ARGUMENT_LIST);
- assertSuggestImportedFunction(
- 'hasLength', 'bool', kind: CompletionSuggestionKind.IDENTIFIER);
+ assertSuggestImportedFunction('hasLength', 'bool',
+ kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestImportedFunction('identical', 'bool',
kind: CompletionSuggestionKind.IDENTIFIER);
assertSuggestLocalClass('B', kind: CompletionSuggestionKind.IDENTIFIER);
@@ -1280,7 +1282,10 @@
// 'num',
// false,
// COMPLETION_RELEVANCE_LOW);
- assertSuggestTopLevelVarGetterSetter('T1', 'String');
+ if (computer is ImportedComputer) {
+ // TODO(danrubel) should be top level var suggestion
+ assertSuggestGetter('T1', 'String');
+ }
assertNotSuggested('_T2');
//assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
assertNotSuggested('_T4');
@@ -1313,6 +1318,7 @@
addSource('/testG.dart', 'class G { }');
addSource('/testH.dart', '''
class H { }
+ class D3 { }
int T3;
var _T4;'''); // not imported
addTestSource('''
@@ -1345,9 +1351,11 @@
//assertSuggestImportedClass('C');
// hidden element suggested as low relevance
assertSuggestImportedClass('D', relevance: DART_RELEVANCE_LOW);
- assertSuggestImportedFunction(
- 'D1', null, deprecated: true, relevance: DART_RELEVANCE_LOW);
+ assertSuggestImportedFunction('D1', null,
+ deprecated: true, relevance: DART_RELEVANCE_LOW);
assertSuggestLocalFunction('D2', 'Z');
+ // unimported elements suggested with low relevance
+ assertSuggestImportedClass('D3', relevance: DART_RELEVANCE_LOW);
//assertSuggestImportedClass('EE');
// hidden element suggested as low relevance
//assertSuggestImportedClass('F', COMPLETION_RELEVANCE_LOW);
@@ -1430,6 +1438,18 @@
});
}
+ test_Block_unimported() {
+ addSource('/testAB.dart', 'class Foo { }');
+ addTestSource('class C {foo(){F^}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ assertSuggestImportedClass('Foo', relevance: DART_RELEVANCE_LOW);
+ assertSuggestImportedClass('Future', relevance: DART_RELEVANCE_LOW);
+ });
+ }
+
test_CascadeExpression_selector1() {
// PropertyAccess CascadeExpression ExpressionStatement Block
addSource('/testB.dart', '''
@@ -2355,6 +2375,7 @@
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;}
@@ -2364,6 +2385,7 @@
expect(request.replacementOffset, completionOffset);
expect(request.replacementLength, 0);
assertSuggestImportedConstructor('Object');
+ assertSuggestImportedConstructor('Future');
assertSuggestImportedConstructor('A');
assertSuggestLocalConstructor('B');
assertSuggestLocalConstructor('C');
@@ -2377,6 +2399,19 @@
});
}
+ test_InstanceCreationExpression_unimported() {
+ // SimpleIdentifier TypeName ConstructorName InstanceCreationExpression
+ addSource('/testAB.dart', 'class Foo { }');
+ addTestSource('class C {foo(){new F^}}');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ assertSuggestImportedConstructor('Foo', relevance: DART_RELEVANCE_LOW);
+ assertSuggestImportedConstructor('Future', relevance: DART_RELEVANCE_LOW);
+ });
+ }
+
test_InterpolationExpression() {
// SimpleIdentifier InterpolationExpression StringInterpolation
addSource('/testA.dart', '''
@@ -2589,7 +2624,9 @@
assertSuggestImportedFunction('nowIsIt', null);
assertNotSuggested('T1');
// TODO (danrubel) this really should be TopLevelVar not getter/setter
- assertSuggestTopLevelVarGetterSetter('newT1', 'int');
+ if (computer is ImportedComputer) {
+ assertSuggestGetter('newT1', 'int');
+ }
assertNotSuggested('z');
assertSuggestLocalTopLevelVar('m', 'dynamic');
assertSuggestLocalFunction('newer', 'String');
@@ -2625,6 +2662,94 @@
});
}
+ test_MapLiteralEntry() {
+ // 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 = {^''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestImportedClass('Object');
+ // TODO(danrubel) Should be top level variable
+ if (computer is ImportedComputer) {
+ assertSuggestGetter('T1', 'int');
+ // assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+ assertSuggestImportedFunction('F1', null);
+ assertSuggestImportedFunctionTypeAlias('D1', null);
+ assertSuggestImportedClass('C1');
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ assertSuggestLocalFunction('F2', null);
+ assertSuggestLocalFunctionTypeAlias('D2', null);
+ assertSuggestLocalClass('C2');
+ });
+ }
+
+ test_MapLiteralEntry1() {
+ // 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^''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ // TODO(danrubel) Should be top level variable
+ if (computer is ImportedComputer) {
+ assertSuggestGetter('T1', 'int');
+ // assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ });
+ }
+
+ test_MapLiteralEntry2() {
+ // 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^};''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ // TODO(danrubel) Should be top level variable
+ if (computer is ImportedComputer) {
+ assertSuggestGetter('T1', 'int');
+ // assertSuggestImportedTopLevelVar('T1', 'int');
+ }
+ assertSuggestLocalTopLevelVar('T2', 'int');
+ });
+ }
+
test_MethodDeclaration_body_getters() {
// Block BlockFunctionBody MethodDeclaration
addTestSource('class A {@deprecated X get f => 0; Z a() {^} get _g => 1;}');
@@ -3400,6 +3525,55 @@
});
}
+ test_TypeArgumentList() {
+ // SimpleIdentifier BinaryExpression ExpressionStatement
+ addSource('/testA.dart', '''
+ class C1 {int x;}
+ F1() => 0;
+ typedef String T1(int blat);''');
+ addTestSource('''
+ import "/testA.dart";'
+ class C2 {int x;}
+ F2() => 0;
+ typedef int T2(int blat);
+ class C<E> {}
+ main() { C<^> c; }''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset);
+ expect(request.replacementLength, 0);
+ assertSuggestImportedClass('Object');
+ assertSuggestImportedClass('C1');
+ assertSuggestImportedFunctionTypeAlias('T1', 'String');
+ assertSuggestLocalClass('C2');
+ assertSuggestLocalFunctionTypeAlias('T2', 'int');
+ assertNotSuggested('F1');
+ assertNotSuggested('F2');
+ });
+ }
+
+ test_TypeArgumentList2() {
+ // TypeName TypeArgumentList TypeName
+ addSource('/testA.dart', '''
+ class C1 {int x;}
+ F1() => 0;
+ typedef String T1(int blat);''');
+ addTestSource('''
+ import "/testA.dart";'
+ class C2 {int x;}
+ F2() => 0;
+ typedef int T2(int blat);
+ class C<E> {}
+ main() { C<C^> c; }''');
+ computeFast();
+ return computeFull((bool result) {
+ expect(request.replacementOffset, completionOffset - 1);
+ expect(request.replacementLength, 1);
+ assertSuggestImportedClass('C1');
+ assertSuggestLocalClass('C2');
+ });
+ }
+
test_VariableDeclaration_name() {
// SimpleIdentifier VariableDeclaration VariableDeclarationList
// VariableDeclarationStatement Block
diff --git a/pkg/analysis_server/test/services/completion/imported_computer_test.dart b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
index 51870d0..fd323e2 100644
--- a/pkg/analysis_server/test/services/completion/imported_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/imported_computer_test.dart
@@ -117,8 +117,9 @@
}
@override
- CompletionSuggestion assertSuggestImportedConstructor(String name) {
- return assertSuggestConstructor(name);
+ CompletionSuggestion assertSuggestImportedConstructor(String name,
+ {int relevance: DART_RELEVANCE_DEFAULT}) {
+ return assertSuggestConstructor(name, relevance: relevance);
}
@override
@@ -592,9 +593,6 @@
}
test_mixin_ordering() {
- // TODO(paulberry): The mixins are visited in the correct order, so we see
- // M2.m() before M1.m(), as we should. But the second (shadowed) result
- // isn't being thrown out as it should.
addSource('/libA.dart', '''
class B {}
class M1 {
diff --git a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
index 3cd9d67..16fcb6ec 100644
--- a/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/invocation_computer_test.dart
@@ -137,6 +137,22 @@
});
}
+ test_libraryPrefix() {
+ // SimpleIdentifier PrefixedIdentifier ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^}');
+ return computeFull((bool result) {
+ assertSuggestClass('Future');
+ });
+ }
+
+ test_libraryPrefix2() {
+ // SimpleIdentifier MethodInvocation ExpressionStatement
+ addTestSource('import "dart:async" as bar; foo() {bar.^ print("f")}');
+ return computeFull((bool result) {
+ assertSuggestClass('Future');
+ });
+ }
+
test_local() {
addTestSource('foo() {String x = "bar"; x.^}');
return computeFull((bool result) {
@@ -399,7 +415,7 @@
check_shadowing('int x;', 'set x(int value) {}', true);
test_shadowing_getter_over_field() =>
- check_shadowing('int get x => null;', 'int x;', false);
+ check_shadowing('int get x => null;', 'int x;', true);
test_shadowing_getter_over_getter() =>
check_shadowing('int get x => null;', 'int get x => null;', true);
@@ -408,7 +424,7 @@
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);
+ check_shadowing('int get x => null;', 'set x(int value) {}', true);
test_shadowing_method_over_field() =>
check_shadowing('void x() {}', 'int x;', true);
@@ -468,10 +484,10 @@
}
test_shadowing_setter_over_field() =>
- check_shadowing('set x(int value) {}', 'int x;', false);
+ check_shadowing('set x(int value) {}', 'int x;', true);
test_shadowing_setter_over_getter() =>
- check_shadowing('set x(int value) {}', 'int get x => null;', false);
+ check_shadowing('set x(int value) {}', 'int get x => null;', true);
test_shadowing_setter_over_method() =>
check_shadowing('set x(int value) {}', 'void x() {}', true);
diff --git a/pkg/analysis_server/test/services/completion/local_computer_test.dart b/pkg/analysis_server/test/services/completion/local_computer_test.dart
index 05182d3..fed9d0f 100644
--- a/pkg/analysis_server/test/services/completion/local_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_computer_test.dart
@@ -194,6 +194,15 @@
assertNotSuggested('x');
}
+ test_overrides() {
+ addTestSource('''
+class A {m() {}}
+class B extends A {m() {^}}
+''');
+ expect(computeFast(), isTrue);
+ assertSuggestMethod('m', 'B', null, relevance: DART_RELEVANCE_LOCAL_METHOD);
+ }
+
test_break_ignores_unrelated_statements() {
addTestSource('''
void main() {
@@ -225,6 +234,41 @@
assertSuggestLabel('bar');
}
+ test_constructor_parameters_mixed_required_and_named() {
+ addTestSource('class A {A(x, {int y}) {^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestParameter('x', null);
+ assertSuggestParameter('y', 'int');
+ }
+
+ test_constructor_parameters_mixed_required_and_positional() {
+ addTestSource('class A {A(x, [int y]) {^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestParameter('x', null);
+ assertSuggestParameter('y', 'int');
+ }
+
+ test_constructor_parameters_named() {
+ addTestSource('class A {A({x, int y}) {^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestParameter('x', null);
+ assertSuggestParameter('y', 'int');
+ }
+
+ test_constructor_parameters_positional() {
+ addTestSource('class A {A([x, int y]) {^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestParameter('x', null);
+ assertSuggestParameter('y', 'int');
+ }
+
+ test_constructor_parameters_required() {
+ addTestSource('class A {A(x, int y) {^}}');
+ expect(computeFast(), isTrue);
+ assertSuggestParameter('x', null);
+ assertSuggestParameter('y', 'int');
+ }
+
test_continue_from_loop_to_switch() {
addTestSource('''
void main() {
@@ -698,4 +742,10 @@
expect(suggestion.requiredParameterCount, 2);
expect(suggestion.hasNamedParameters, false);
}
+
+ test_shadowed_name() {
+ addTestSource('var a; class A { var a; m() { ^ } }');
+ expect(computeFast(), isTrue);
+ assertSuggestLocalField('a', null);
+ }
}
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index 9ff44e5..897fb20 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -178,6 +178,12 @@
assertOpType(returnValue: true, typeNames: true);
}
+ test_BinaryExpression_RHS2() {
+ // SimpleIdentifier BinaryExpression
+ addTestSource('main() {if (c < ^)}');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
test_Block() {
// Block BlockFunctionBody MethodDeclaration
addTestSource('''
@@ -789,6 +795,24 @@
assertOpType();
}
+ test_MapLiteralEntry() {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {^');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_MapLiteralEntry1() {
+ // MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {T^');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
+ test_MapLiteralEntry2() {
+ // SimpleIdentifier MapLiteralEntry MapLiteral VariableDeclaration
+ addTestSource('foo = {7:T^};');
+ assertOpType(returnValue: true, typeNames: true);
+ }
+
test_MethodDeclaration1() {
// SimpleIdentifier MethodDeclaration ClassDeclaration
addTestSource('class Bar {const ^Fara();}');
@@ -1046,6 +1070,18 @@
assertOpType();
}
+ test_TypeArgumentList() {
+ // SimpleIdentifier BinaryExpression ExpressionStatement
+ addTestSource('main() { C<^> c; }');
+ assertOpType(typeNames: true);
+ }
+
+ test_TypeArgumentList2() {
+ // TypeName TypeArgumentList TypeName
+ addTestSource('main() { C<C^> c; }');
+ assertOpType(typeNames: true);
+ }
+
test_TypeParameter() {
// SimpleIdentifier TypeParameter TypeParameterList
addTestSource('class tezetst <String, ^List> {}');
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 399959c..bf4be15 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -451,6 +451,13 @@
void set sourceFactory(SourceFactory factory);
/**
+ * Return an array containing all of the sources known to this context.
+ *
+ * @return all of the sources known to this context
+ */
+ List<Source> get sources;
+
+ /**
* Returns a type provider for this context or throws [AnalysisException] if
* `dart:core` or `dart:async` cannot be resolved.
*/
@@ -1447,6 +1454,16 @@
_invalidateAllLocalResolutionInformation(true);
}
+ @override
+ List<Source> get sources {
+ List<Source> sources = new List<Source>();
+ MapIterator<Source, SourceEntry> iterator = _cache.iterator();
+ while (iterator.moveNext()) {
+ sources.add(iterator.key);
+ }
+ return sources;
+ }
+
/**
* Return a list of the sources that would be processed by [performAnalysisTask]. This
* method duplicates, and must therefore be kept in sync with, [getNextAnalysisTask].
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index fb22d61..b56b46a 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -3737,7 +3737,7 @@
indexField.type = intType;
fields.add(indexField);
getters.add(_createGetter(indexField));
- FieldElementImpl valuesField = new FieldElementImpl("values", -1);
+ ConstFieldElementImpl valuesField = new ConstFieldElementImpl.con2("values", -1);
valuesField.static = true;
valuesField.const3 = true;
valuesField.synthetic = true;
@@ -3748,6 +3748,7 @@
// Build the enum constants.
//
NodeList<EnumConstantDeclaration> constants = node.constants;
+ List<DartObjectImpl> constantValues = new List<DartObjectImpl>();
int constantCount = constants.length;
for (int i = 0; i < constantCount; i++) {
SimpleIdentifier constantName = constants[i].name;
@@ -3764,12 +3765,17 @@
fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i));
DartObjectImpl value =
new DartObjectImpl(enumType, new GenericState(fieldMap));
+ constantValues.add(value);
constantField.evaluationResult = new EvaluationResultImpl.con1(value);
fields.add(constantField);
getters.add(_createGetter(constantField));
constantName.staticElement = constantField;
}
//
+ // Build the value of the 'values' field.
+ //
+ valuesField.evaluationResult = new EvaluationResultImpl.con1(new DartObjectImpl(valuesField.type, new ListState(constantValues)));
+ //
// Finish building the enum.
//
enumElement.fields = fields;
@@ -14843,6 +14849,17 @@
}
@override
+ Object visitMethodDeclaration(MethodDeclaration node) {
+ ExecutableElement outerFunction = _enclosingFunction;
+ try {
+ _enclosingFunction = node.element;
+ return super.visitMethodDeclaration(node);
+ } finally {
+ _enclosingFunction = outerFunction;
+ }
+ }
+
+ @override
Object visitFunctionExpression(FunctionExpression node) {
if (node.parent is! FunctionDeclaration) {
ExecutableElement outerFunction = _enclosingFunction;
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 877a995..2685726 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -1492,7 +1492,6 @@
int next = _reader.advance();
outer: while (next != -1) {
while (next != quoteChar) {
- next = _reader.advance();
if (next == -1) {
break outer;
} else if (next == 0xD) {
@@ -1502,7 +1501,9 @@
}
recordStartOfLine();
} else if (next == 0xA) {
+ next = _reader.advance();
recordStartOfLine();
+ } else {
next = _reader.advance();
}
}
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index 845711d..2c317aa 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -6337,18 +6337,21 @@
expect(constant, isNotNull);
expect(constant.name, firstName);
expect(constant.isStatic, isTrue);
+ expect((constant as FieldElementImpl).evaluationResult, isNotNull);
_assertGetter(constant);
constant = fields[3];
expect(constant, isNotNull);
expect(constant.name, secondName);
expect(constant.isStatic, isTrue);
+ expect((constant as FieldElementImpl).evaluationResult, isNotNull);
_assertGetter(constant);
constant = fields[4];
expect(constant, isNotNull);
expect(constant.name, thirdName);
expect(constant.isStatic, isTrue);
+ expect((constant as FieldElementImpl).evaluationResult, isNotNull);
_assertGetter(constant);
}
@@ -6373,12 +6376,14 @@
expect(field.name, "values");
expect(field.isStatic, isTrue);
expect(field.isSynthetic, isTrue);
+ expect((field as FieldElementImpl).evaluationResult, isNotNull);
_assertGetter(field);
FieldElement constant = fields[2];
expect(constant, isNotNull);
expect(constant.name, firstName);
expect(constant.isStatic, isTrue);
+ expect((constant as FieldElementImpl).evaluationResult, isNotNull);
_assertGetter(constant);
}
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index 0949de7..2b2c5f3 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -5479,11 +5479,16 @@
}
@override
+ List<Source> get sources {
+ fail("Unexpected invocation of sources");
+ return null;
+ }
+
+ @override
AnalysisContextStatistics get statistics {
fail("Unexpected invocation of getStatistics");
return null;
}
-
@override
TypeProvider get typeProvider {
fail("Unexpected invocation of getTypeProvider");
@@ -5734,6 +5739,7 @@
int oldLength, int newLength) {
fail("Unexpected invocation of setChangedContents");
}
+
@override
void setContents(Source source, String contents) {
fail("Unexpected invocation of setContents");
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index ca1eb93..21bc357 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -12600,6 +12600,37 @@
expect(typeProvider.stringType.isSubtypeOf(t), isTrue);
}
+ void test_mutatedOutsideScope() {
+ // https://code.google.com/p/dart/issues/detail?id=22732
+ Source source = addSource(r'''
+class Base {
+}
+
+class Derived extends Base {
+ get y => null;
+}
+
+class C {
+ void f() {
+ Base x = null;
+ if (x is Derived) {
+ print(x.y); // BAD
+ }
+ x = null;
+ }
+}
+
+void g() {
+ Base x = null;
+ if (x is Derived) {
+ print(x.y); // GOOD
+ }
+ x = null;
+}''');
+ resolve(source);
+ assertNoErrors(source);
+ }
+
void test_objectMethodOnDynamicExpression_doubleEquals() {
// https://code.google.com/p/dart/issues/detail?id=20342
//
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 19e2a02..b65bd51 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -20,54 +20,6 @@
runReflectiveTests(TokenTypeTest);
}
-@reflectiveTest
-class CharSequenceReaderTest {
- void test_advance() {
- CharSequenceReader reader = new CharSequenceReader("x");
- expect(reader.advance(), 0x78);
- expect(reader.advance(), -1);
- expect(reader.advance(), -1);
- }
-
- void test_creation() {
- expect(new CharSequenceReader("x"), isNotNull);
- }
-
- void test_getOffset() {
- CharSequenceReader reader = new CharSequenceReader("x");
- expect(reader.offset, -1);
- reader.advance();
- expect(reader.offset, 0);
- reader.advance();
- expect(reader.offset, 0);
- }
-
- void test_getString() {
- CharSequenceReader reader = new CharSequenceReader("xyzzy");
- reader.offset = 3;
- expect(reader.getString(1, 0), "yzz");
- expect(reader.getString(2, 1), "zzy");
- }
-
- void test_peek() {
- CharSequenceReader reader = new CharSequenceReader("xy");
- expect(reader.peek(), 0x78);
- expect(reader.peek(), 0x78);
- reader.advance();
- expect(reader.peek(), 0x79);
- expect(reader.peek(), 0x79);
- reader.advance();
- expect(reader.peek(), -1);
- expect(reader.peek(), -1);
- }
-
- void test_setOffset() {
- CharSequenceReader reader = new CharSequenceReader("xyz");
- reader.offset = 2;
- expect(reader.offset, 2);
- }
-}
-
class CharacterRangeReaderTest extends EngineTestCase {
void test_advance() {
CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
@@ -125,6 +77,54 @@
}
@reflectiveTest
+class CharSequenceReaderTest {
+ void test_advance() {
+ CharSequenceReader reader = new CharSequenceReader("x");
+ expect(reader.advance(), 0x78);
+ expect(reader.advance(), -1);
+ expect(reader.advance(), -1);
+ }
+
+ void test_creation() {
+ expect(new CharSequenceReader("x"), isNotNull);
+ }
+
+ void test_getOffset() {
+ CharSequenceReader reader = new CharSequenceReader("x");
+ expect(reader.offset, -1);
+ reader.advance();
+ expect(reader.offset, 0);
+ reader.advance();
+ expect(reader.offset, 0);
+ }
+
+ void test_getString() {
+ CharSequenceReader reader = new CharSequenceReader("xyzzy");
+ reader.offset = 3;
+ expect(reader.getString(1, 0), "yzz");
+ expect(reader.getString(2, 1), "zzy");
+ }
+
+ void test_peek() {
+ CharSequenceReader reader = new CharSequenceReader("xy");
+ expect(reader.peek(), 0x78);
+ expect(reader.peek(), 0x78);
+ reader.advance();
+ expect(reader.peek(), 0x79);
+ expect(reader.peek(), 0x79);
+ reader.advance();
+ expect(reader.peek(), -1);
+ expect(reader.peek(), -1);
+ }
+
+ void test_setOffset() {
+ CharSequenceReader reader = new CharSequenceReader("xyz");
+ reader.offset = 2;
+ expect(reader.offset, 2);
+ }
+}
+
+@reflectiveTest
class KeywordStateTest {
void test_KeywordState() {
//
@@ -593,6 +593,15 @@
]);
}
+ void test_lineInfo_multilineString_raw() {
+ String source = "var a = r'''\nblah\n''';\n\nfoo";
+ _assertLineInfo(source, [
+ new ScannerTest_ExpectedLocation(0, 1, 1),
+ new ScannerTest_ExpectedLocation(14, 2, 2),
+ new ScannerTest_ExpectedLocation(source.length - 2, 5, 2)
+ ]);
+ }
+
void test_lineInfo_simpleClass() {
String source =
"class Test {\r\n String s = '...';\r\n int get x => s.MISSING_GETTER;\r\n}";
@@ -639,10 +648,6 @@
_assertToken(TokenType.MINUS_MINUS, "--");
}
- void test_openSquareBracket() {
- _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
- }
-
void test_open_curly_bracket() {
_assertToken(TokenType.OPEN_CURLY_BRACKET, "{");
}
@@ -655,6 +660,10 @@
_assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
}
+ void test_openSquareBracket() {
+ _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
+ }
+
void test_percent() {
_assertToken(TokenType.PERCENT, "%");
}
@@ -667,6 +676,14 @@
_assertToken(TokenType.PERIOD, ".");
}
+ void test_period_period() {
+ _assertToken(TokenType.PERIOD_PERIOD, "..");
+ }
+
+ void test_period_period_period() {
+ _assertToken(TokenType.PERIOD_PERIOD_PERIOD, "...");
+ }
+
void test_periodAfterNumberNotIncluded_identifier() {
_assertTokens("42.isEven()", [
new StringToken(TokenType.INT, "42", 0),
@@ -687,14 +704,6 @@
]);
}
- void test_period_period() {
- _assertToken(TokenType.PERIOD_PERIOD, "..");
- }
-
- void test_period_period_period() {
- _assertToken(TokenType.PERIOD_PERIOD_PERIOD, "...");
- }
-
void test_plus() {
_assertToken(TokenType.PLUS, "+");
}
@@ -715,14 +724,14 @@
_assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart -debug");
}
- void test_scriptTag_withSpace() {
- _assertToken(TokenType.SCRIPT_TAG, "#! /bin/dart");
- }
-
void test_scriptTag_withoutSpace() {
_assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart");
}
+ void test_scriptTag_withSpace() {
+ _assertToken(TokenType.SCRIPT_TAG, "#! /bin/dart");
+ }
+
void test_semicolon() {
_assertToken(TokenType.SEMICOLON, ";");
}
@@ -840,8 +849,8 @@
void test_string_raw_multi_unterminated() {
String source = "r'''string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- 9, source, [new StringToken(TokenType.STRING, source, 0)]);
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
}
void test_string_raw_simple_double() {
@@ -854,14 +863,14 @@
void test_string_raw_simple_unterminated_eof() {
String source = "r'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- 7, source, [new StringToken(TokenType.STRING, source, 0)]);
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
}
void test_string_raw_simple_unterminated_eol() {
String source = "r'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- 8, "$source\n", [new StringToken(TokenType.STRING, source, 0)]);
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
+ "$source\n", [new StringToken(TokenType.STRING, source, 0)]);
}
void test_string_simple_double() {
@@ -957,14 +966,14 @@
void test_string_simple_unterminated_eof() {
String source = "'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- 6, source, [new StringToken(TokenType.STRING, source, 0)]);
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6,
+ source, [new StringToken(TokenType.STRING, source, 0)]);
}
void test_string_simple_unterminated_eol() {
String source = "'string";
- _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- 7, "$source\r", [new StringToken(TokenType.STRING, source, 0)]);
+ _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
+ "$source\r", [new StringToken(TokenType.STRING, source, 0)]);
}
void test_string_simple_unterminated_interpolation_block() {
@@ -1044,9 +1053,8 @@
GatheringErrorListener listener = new GatheringErrorListener();
_scanWithListener(source, listener);
listener.assertErrors([
- new AnalysisError.con2(null, expectedOffset, 1, expectedError, [
- source.codeUnitAt(expectedOffset)
- ])
+ new AnalysisError.con2(null, expectedOffset, 1, expectedError,
+ [source.codeUnitAt(expectedOffset)])
]);
}
@@ -1064,9 +1072,8 @@
GatheringErrorListener listener = new GatheringErrorListener();
Token token = _scanWithListener(source, listener);
listener.assertErrors([
- new AnalysisError.con2(null, expectedOffset, 1, expectedError, [
- source.codeUnitAt(expectedOffset)
- ])
+ new AnalysisError.con2(null, expectedOffset, 1, expectedError,
+ [source.codeUnitAt(expectedOffset)])
]);
_checkTokens(token, expectedTokens);
}
@@ -1104,10 +1111,14 @@
listener.assertNoErrors();
LineInfo info = listener.getLineInfo(new TestSource());
expect(info, isNotNull);
- for (ScannerTest_ExpectedLocation expectedLocation in expectedLocations) {
+ int count = expectedLocations.length;
+ for (int i = 0; i < count; i++) {
+ ScannerTest_ExpectedLocation expectedLocation = expectedLocations[i];
LineInfo_Location location = info.getLocation(expectedLocation._offset);
- expect(location.lineNumber, expectedLocation._lineNumber);
- expect(location.columnNumber, expectedLocation._columnNumber);
+ expect(location.lineNumber, expectedLocation._lineNumber,
+ reason: 'Line number in location $i');
+ expect(location.columnNumber, expectedLocation._columnNumber,
+ reason: 'Column number in location $i');
}
}
diff --git a/pkg/analyzer/test/src/task/driver_test.dart b/pkg/analyzer/test/src/task/driver_test.dart
index f82d327..4eb0e0b 100644
--- a/pkg/analyzer/test/src/task/driver_test.dart
+++ b/pkg/analyzer/test/src/task/driver_test.dart
@@ -514,6 +514,9 @@
}
@override
+ List<Source> get sources => baseContext.sources;
+
+ @override
AnalysisContextStatistics get statistics => baseContext.statistics;
@override
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 6540829..0f1f433 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -399,11 +399,14 @@
// Note that RegExes, js.ArrayInitializer and js.ObjectInitializer are not
// [js.Literal]s.
if (result is js.Literal) return result;
+
js.Expression tempVar = useTempVar(allocateTempVar());
addStatement(js.js.statement('# = #;', [tempVar, result]));
return tempVar;
}
+ // TODO(sigurdm): This is obsolete - all calls use store: false. Replace with
+ // visitExpression(node);
withExpression(js.Expression node, fn(js.Expression result), {bool store}) {
int oldTempVarIndex = currentTempVarIndex;
js.Expression visited = visitExpression(node);
@@ -415,6 +418,46 @@
return result;
}
+ /// Calls [fn] with the result of evaluating [node]. Taking special care of
+ /// property accesses.
+ ///
+ /// If [store] is true the result of evaluating [node] is stored in a
+ /// temporary.
+ ///
+ /// We cannot rewrite `<receiver>.m()` to:
+ /// temp = <receiver>.m;
+ /// temp();
+ /// Because this leaves `this` unbound in the call. But because of dart
+ /// evaluation order we can write:
+ /// temp = <receiver>;
+ /// temp.m();
+ withCallTargetExpression(js.Expression node,
+ fn(js.Expression result), {bool store}) {
+ int oldTempVarIndex = currentTempVarIndex;
+ js.Expression visited = visitExpression(node);
+ js.Expression selector;
+ js.Expression storedIfNeeded;
+ if (store) {
+ if (visited is js.PropertyAccess) {
+ js.PropertyAccess propertyAccess = visited;
+ selector = propertyAccess.selector;
+ visited = propertyAccess.receiver;
+ }
+ storedIfNeeded = _storeIfNecessary(visited);
+ } else {
+ storedIfNeeded = visited;
+ }
+ js.Expression result;
+ if (selector == null) {
+ result = fn(storedIfNeeded);
+ } else {
+ result = fn(new js.PropertyAccess(storedIfNeeded, selector));
+ }
+ currentTempVarIndex = oldTempVarIndex;
+ return result;
+ }
+
+
/// Calls [fn] with the value of evaluating [node1] and [node2].
///
/// If `shouldTransform(node2)` the first expression is stored in a temporary
@@ -761,11 +804,11 @@
js.Statement assignLeft = isResult(left)
? new js.Block.empty()
: js.js.statement('# = #;', [result, left]);
- if (node.op == "||") {
+ if (node.op == "&&") {
addStatement(js.js.statement('if (#) {#} else #',
[left, gotoAndBreak(thenLabel), assignLeft]));
} else {
- assert(node.op == "&&");
+ assert(node.op == "||");
addStatement(js.js.statement('if (#) {#} else #',
[left, assignLeft, gotoAndBreak(thenLabel)]));
}
@@ -805,7 +848,7 @@
@override
js.Expression visitCall(js.Call node) {
bool storeTarget = node.arguments.any(shouldTransform);
- return withExpression(node.target, (target) {
+ return withCallTargetExpression(node.target, (target) {
return withExpressions(node.arguments, (List<js.Expression> arguments) {
return new js.Call(target, arguments);
});
@@ -920,7 +963,8 @@
bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable;
insideUntranslatedBreakable = true;
withExpression(node.condition, (js.Expression condition) {
- addStatement(js.js.statement('do {#} while (#)', [node.body, condition]));
+ addStatement(js.js.statement('do {#} while (#)',
+ [node.body, condition]));
}, store: false);
insideUntranslatedBreakable = oldInsideUntranslatedBreakable;
return;
@@ -1148,7 +1192,7 @@
@override
js.Expression visitNew(js.New node) {
bool storeTarget = node.arguments.any(shouldTransform);
- return withExpression(node.target, (target) {
+ return withCallTargetExpression(node.target, (target) {
return withExpressions(node.arguments, (List<js.Expression> arguments) {
return new js.New(target, arguments);
});
@@ -1777,7 +1821,8 @@
js.VariableDeclarationList variableDeclarations) {
// Each iterator invocation on the iterable should work on its own copy of
// the parameters.
- // TODO(sigurdm): We only need to do this copying for parameters that are mutated.
+ // TODO(sigurdm): We only need to do this copying for parameters that are
+ // mutated.
List<js.VariableInitialization> declarations =
new List<js.VariableInitialization>();
List<js.Parameter> renamedParameters = new List<js.Parameter>();
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index 4fe35e5..18db66c 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -243,7 +243,9 @@
class ExpressionStatement extends Statement {
final Expression expression;
- ExpressionStatement(this.expression);
+ ExpressionStatement(this.expression) {
+ assert(this.expression != null);
+ }
accept(NodeVisitor visitor) => visitor.visitExpressionStatement(this);
void visitChildren(NodeVisitor visitor) { expression.accept(visitor); }
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index 2483ceb..be164df6 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -262,12 +262,13 @@
case 0:
// Function start
__temp1 = foo1();
- if (__temp1) {
+ if (__temp1)
+ __result = __temp1;
+ else {
// goto then
__goto = 2;
break;
- } else
- __result = __temp1;
+ }
// goto join
__goto = 3;
break;
@@ -290,12 +291,13 @@
case 8:
// returning from await.
__temp1 = __result;
- if (__temp1) {
+ if (__temp1)
+ __result = __temp1;
+ else {
// goto then
__goto = 6;
break;
- } else
- __result = __temp1;
+ }
// goto join
__goto = 7;
break;
@@ -312,13 +314,12 @@
c = __result;
d = foo1() || foo2();
__temp1 = foo1();
- if (__temp1)
- __result = __temp1;
- else {
+ if (__temp1) {
// goto then
__goto = 10;
break;
- }
+ } else
+ __result = __temp1;
// goto join
__goto = 11;
break;
@@ -341,13 +342,12 @@
case 16:
// returning from await.
__temp1 = __result;
- if (__temp1)
- __result = __temp1;
- else {
+ if (__temp1) {
// goto then
__goto = 14;
break;
- }
+ } else
+ __result = __temp1;
// goto join
__goto = 15;
break;
diff --git a/tests/language/async_and_or_test.dart b/tests/language/async_and_or_test.dart
new file mode 100644
index 0000000..78a3758
--- /dev/null
+++ b/tests/language/async_and_or_test.dart
@@ -0,0 +1,88 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+@NoInline
+@AssumeDynamic
+confuse(x) {
+ return x;
+}
+
+test1() async {
+ Expect.isFalse(await confuse(false) && await confuse(false));
+ Expect.isFalse(await confuse(false) && await confuse(true));
+ Expect.isFalse(await confuse(true) && await confuse(false));
+ Expect.isTrue(await confuse(true) && await confuse(true));
+
+ Expect.isFalse(await confuse(false) || await confuse(false));
+ Expect.isTrue(await confuse(false) || await confuse(true));
+ Expect.isTrue(await confuse(true) || await confuse(false));
+ Expect.isTrue(await confuse(true) || await confuse(true));
+}
+
+String trace;
+
+traceA(x) {
+ trace += "a";
+ return x;
+}
+traceB(x) {
+ trace += "b";
+ return x;
+}
+
+testEvaluation(void fn()) async {
+ trace = "";
+ await fn();
+}
+
+test2() async {
+ await testEvaluation(() async {
+ Expect.isFalse(
+ await confuse(traceA(false)) && await confuse(traceB(false)));
+ Expect.equals("a", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isFalse(await confuse(traceA(false)) && await confuse(traceB(true)));
+ Expect.equals("a", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isFalse(await confuse(traceA(true)) && await confuse(traceB(false)));
+ Expect.equals("ab", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isTrue(await confuse(traceA(true)) && await confuse(traceB(true)));
+ Expect.equals("ab", trace);
+ });
+
+ await testEvaluation(() async {
+ Expect.isFalse(
+ await confuse(traceA(false)) || await confuse(traceB(false)));
+ Expect.equals("ab", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isTrue(await confuse(traceA(false)) || await confuse(traceB(true)));
+ Expect.equals("ab", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isTrue(await confuse(traceA(true)) || await confuse(traceB(false)));
+ Expect.equals("a", trace);
+ });
+ await testEvaluation(() async {
+ Expect.isTrue(await confuse(traceA(true)) || await confuse(traceB(true)));
+ Expect.equals("a", trace);
+ });
+
+}
+
+test() async {
+ await test1();
+ await test2();
+}
+
+main() {
+ asyncStart();
+ test().then((_) => asyncEnd());
+}
diff --git a/tests/language/async_this_bound_test.dart b/tests/language/async_this_bound_test.dart
new file mode 100644
index 0000000..8757f03
--- /dev/null
+++ b/tests/language/async_this_bound_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+class A {
+ int a = -1;
+
+ @NoInline()
+ foo(ignored, val) {
+ Expect.equals(val, this.a);
+ }
+}
+
+testA() async {
+ var a = new A();
+ a.foo(await false, -1);
+ a.a = 0;
+ a.foo(await false, 0);
+}
+
+@NoInline()
+@AssumeDynamic()
+confuse(x) => x;
+
+class B {
+ var f;
+ @NoInline()
+ var b = 10;
+ B(this.f);
+
+ bar(x) => b;
+}
+
+foo(x) => 499;
+bar(x) => 42;
+
+change(x) {
+ x.f = (x) => 99;
+}
+
+testB() async {
+ var b = confuse(new B(foo));
+ Expect.equals(99, b.f(await change(b)));
+ var b2 = confuse(new B(bar));
+ Expect.equals(10, b2.f(await (b2.f = b2.bar)));
+}
+
+test() async {
+ await testA();
+ await testB();
+}
+
+void main() {
+ asyncStart();
+ test().then((_) => asyncEnd());
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index c00da2d..f71127e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 9
PATCH 0
PRERELEASE 10
-PRERELEASE_PATCH 6
+PRERELEASE_PATCH 7