| Index: pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
|
| 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 36d403b4ca6886c3eb967345e1d6b71c1f8f5760..f688f2fa0100ec573e5bcbd7e328ea2e8abf86e3 100644
|
| --- a/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
|
| +++ b/pkg/analysis_server/lib/src/services/completion/keyword_computer.dart
|
| @@ -18,7 +18,7 @@ import 'package:analyzer/src/generated/scanner.dart';
|
| class KeywordComputer extends DartCompletionComputer {
|
| @override
|
| bool computeFast(DartCompletionRequest request) {
|
| - request.node.accept(new _KeywordVisitor(request));
|
| + request.target.containingNode.accept(new _KeywordVisitor(request));
|
| return true;
|
| }
|
|
|
| @@ -33,67 +33,44 @@ class KeywordComputer extends DartCompletionComputer {
|
| */
|
| class _KeywordVisitor extends GeneralizingAstVisitor {
|
| final DartCompletionRequest request;
|
| + final Object entity;
|
|
|
| - /**
|
| - * The identifier visited or `null` if not visited.
|
| - */
|
| - SimpleIdentifier identifier;
|
| -
|
| - _KeywordVisitor(this.request);
|
| + _KeywordVisitor(DartCompletionRequest request)
|
| + : this.request = request,
|
| + this.entity = request.target.entity;
|
|
|
| @override
|
| visitBlock(Block node) {
|
| if (_isInClassMemberBody(node)) {
|
| - _addSuggestions([
|
| - Keyword.ASSERT,
|
| - Keyword.CASE,
|
| - Keyword.CONTINUE,
|
| - Keyword.DO,
|
| - Keyword.FINAL,
|
| - Keyword.FOR,
|
| - Keyword.IF,
|
| - Keyword.NEW,
|
| - Keyword.RETHROW,
|
| - Keyword.RETURN,
|
| - Keyword.SUPER,
|
| - Keyword.SWITCH,
|
| - Keyword.THIS,
|
| - Keyword.THROW,
|
| - Keyword.TRY,
|
| - Keyword.VAR,
|
| - Keyword.VOID,
|
| - Keyword.WHILE
|
| - ]);
|
| - } else {
|
| - _addSuggestions([
|
| - Keyword.ASSERT,
|
| - Keyword.CASE,
|
| - Keyword.CONTINUE,
|
| - Keyword.DO,
|
| - Keyword.FINAL,
|
| - Keyword.FOR,
|
| - Keyword.IF,
|
| - Keyword.NEW,
|
| - Keyword.RETHROW,
|
| - Keyword.RETURN,
|
| - Keyword.SWITCH,
|
| - Keyword.THROW,
|
| - Keyword.TRY,
|
| - Keyword.VAR,
|
| - Keyword.VOID,
|
| - Keyword.WHILE
|
| - ]);
|
| + _addSuggestions([Keyword.SUPER, Keyword.THIS,]);
|
| }
|
| + _addSuggestions([
|
| + Keyword.ASSERT,
|
| + Keyword.CASE,
|
| + Keyword.CONTINUE,
|
| + Keyword.DO,
|
| + Keyword.FINAL,
|
| + Keyword.FOR,
|
| + Keyword.IF,
|
| + Keyword.NEW,
|
| + Keyword.RETHROW,
|
| + Keyword.RETURN,
|
| + Keyword.SWITCH,
|
| + Keyword.THROW,
|
| + Keyword.TRY,
|
| + Keyword.VAR,
|
| + Keyword.VOID,
|
| + Keyword.WHILE
|
| + ]);
|
| }
|
|
|
| @override
|
| visitClassDeclaration(ClassDeclaration node) {
|
| // Don't suggest class name
|
| - if (node.name == identifier) {
|
| + if (entity == node.name) {
|
| return;
|
| }
|
| - // Inside the class declaration { }
|
| - if (request.offset > node.leftBracket.offset) {
|
| + if (entity == node.rightBracket) {
|
| _addSuggestions([
|
| Keyword.CONST,
|
| Keyword.DYNAMIC,
|
| @@ -113,41 +90,31 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
|
|
|
| @override
|
| visitCompilationUnit(CompilationUnit node) {
|
| - Directive firstDirective;
|
| - int endOfDirectives = 0;
|
| - if (node.directives.length > 0) {
|
| - firstDirective = node.directives[0];
|
| - endOfDirectives = node.directives.last.end - 1;
|
| - }
|
| - int startOfDeclarations = node.end;
|
| - if (node.declarations.length > 0) {
|
| - startOfDeclarations = node.declarations[0].offset;
|
| - // If the first token is a simple identifier
|
| - // and cursor position in within that first token
|
| - // then consider cursor to be before the first declaration
|
| - Token token = node.declarations[0].firstTokenAfterCommentAndMetadata;
|
| - if (token.offset <= request.offset && request.offset <= token.end) {
|
| - startOfDeclarations = token.end;
|
| + var previousMember = null;
|
| + for (var member in node.childEntities) {
|
| + if (entity == member) {
|
| + break;
|
| }
|
| + previousMember = member;
|
| }
|
| -
|
| - // Simplistic check for library as first directive
|
| - if (firstDirective is! LibraryDirective) {
|
| - if (firstDirective != null) {
|
| - if (request.offset <= firstDirective.offset) {
|
| - _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
|
| - }
|
| - } else {
|
| - if (request.offset <= startOfDeclarations) {
|
| - _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
|
| - }
|
| + if (previousMember is ClassDeclaration) {
|
| + if (previousMember.leftBracket == null ||
|
| + previousMember.leftBracket.isSynthetic) {
|
| + // If the prior member is an unfinished class declaration
|
| + // then the user is probably finishing that
|
| + _addClassDeclarationKeywords(previousMember);
|
| + return;
|
| }
|
| }
|
| - if (request.offset <= startOfDeclarations) {
|
| + if (previousMember == null || previousMember is Directive) {
|
| + if (previousMember == null &&
|
| + !node.directives.any((d) => d is LibraryDirective)) {
|
| + _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH);
|
| + }
|
| _addSuggestions(
|
| [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH);
|
| }
|
| - if (request.offset >= endOfDirectives) {
|
| + if (entity == null || entity is Declaration) {
|
| _addSuggestions([
|
| Keyword.ABSTRACT,
|
| Keyword.CLASS,
|
| @@ -159,50 +126,6 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
|
| }
|
| }
|
|
|
| - @override
|
| - visitNode(AstNode node) {
|
| - if (_isOffsetAfterNode(node)) {
|
| - node.parent.accept(this);
|
| - }
|
| - }
|
| -
|
| - visitSimpleIdentifier(SimpleIdentifier node) {
|
| - identifier = node;
|
| - node.parent.accept(this);
|
| - }
|
| -
|
| - void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
| - if (identifier != null && node.beginToken == identifier.beginToken) {
|
| - AstNode unit = node.parent;
|
| - if (unit is CompilationUnit) {
|
| - CompilationUnitMember previous;
|
| - for (CompilationUnitMember member in unit.declarations) {
|
| - if (member == node && previous is ClassDeclaration) {
|
| - if (previous.endToken.isSynthetic) {
|
| - // Partial keywords (simple identifirs) that are part of a
|
| - // class declaration can be parsed
|
| - // as a TypeName in a TopLevelVariableDeclaration
|
| - _addClassDeclarationKeywords(previous);
|
| - return;
|
| - }
|
| - }
|
| - previous = member;
|
| - }
|
| - // Partial keywords (simple identifiers) can be parsed
|
| - // as a TypeName in a TopLevelVariableDeclaration
|
| - unit.accept(this);
|
| - }
|
| - }
|
| - }
|
| -
|
| - void visitTypeName(TypeName node) {
|
| - node.parent.accept(this);
|
| - }
|
| -
|
| - void visitVariableDeclarationList(VariableDeclarationList node) {
|
| - node.parent.accept(this);
|
| - }
|
| -
|
| void _addClassDeclarationKeywords(ClassDeclaration node) {
|
| // Very simplistic suggestion because analyzer will warn if
|
| // the extends / with / implements keywords are out of order
|
| @@ -220,8 +143,8 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
|
| [int relevance = DART_RELEVANCE_DEFAULT]) {
|
| String completion = keyword.syntax;
|
| request.addSuggestion(new CompletionSuggestion(
|
| - CompletionSuggestionKind.KEYWORD,
|
| - relevance, completion, completion.length, 0, false, false));
|
| + CompletionSuggestionKind.KEYWORD, relevance, completion,
|
| + completion.length, 0, false, false));
|
| }
|
|
|
| void _addSuggestions(List<Keyword> keywords,
|
| @@ -231,19 +154,7 @@ class _KeywordVisitor extends GeneralizingAstVisitor {
|
| });
|
| }
|
|
|
| - bool _isOffsetAfterNode(AstNode node) {
|
| - if (request.offset == node.end) {
|
| - Token token = node.endToken;
|
| - if (token != null && !token.isSynthetic) {
|
| - if (token.lexeme == ';' || token.lexeme == '}') {
|
| - return true;
|
| - }
|
| - }
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - static bool _isInClassMemberBody(AstNode node) {
|
| + bool _isInClassMemberBody(AstNode node) {
|
| while (true) {
|
| AstNode body = node.getAncestor((n) => n is FunctionBody);
|
| if (body == null) {
|
|
|