| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 library services.completion.contributor.dart.keyword; | |
| 6 | |
| 7 import 'dart:async'; | |
| 8 | |
| 9 import 'package:analysis_server/src/protocol.dart'; | |
| 10 import 'package:analysis_server/src/services/completion/dart_completion_manager.
dart'; | |
| 11 import 'package:analyzer/src/generated/ast.dart'; | |
| 12 import 'package:analyzer/src/generated/scanner.dart'; | |
| 13 | |
| 14 /** | |
| 15 * A contributor for calculating `completion.getSuggestions` request results | |
| 16 * for the local library in which the completion is requested. | |
| 17 */ | |
| 18 class KeywordContributor extends DartCompletionContributor { | |
| 19 @override | |
| 20 bool computeFast(DartCompletionRequest request) { | |
| 21 request.target.containingNode.accept(new _KeywordVisitor(request)); | |
| 22 return true; | |
| 23 } | |
| 24 | |
| 25 @override | |
| 26 Future<bool> computeFull(DartCompletionRequest request) { | |
| 27 return new Future.value(false); | |
| 28 } | |
| 29 } | |
| 30 | |
| 31 /** | |
| 32 * A vistor for generating keyword suggestions. | |
| 33 */ | |
| 34 class _KeywordVisitor extends GeneralizingAstVisitor { | |
| 35 final DartCompletionRequest request; | |
| 36 final Object entity; | |
| 37 | |
| 38 _KeywordVisitor(DartCompletionRequest request) | |
| 39 : this.request = request, | |
| 40 this.entity = request.target.entity; | |
| 41 | |
| 42 @override | |
| 43 visitBlock(Block node) { | |
| 44 if (_isInClassMemberBody(node)) { | |
| 45 _addSuggestions([Keyword.SUPER, Keyword.THIS,]); | |
| 46 } | |
| 47 _addSuggestions([ | |
| 48 Keyword.ASSERT, | |
| 49 Keyword.CASE, | |
| 50 Keyword.CONTINUE, | |
| 51 Keyword.DO, | |
| 52 Keyword.FINAL, | |
| 53 Keyword.FOR, | |
| 54 Keyword.IF, | |
| 55 Keyword.NEW, | |
| 56 Keyword.RETHROW, | |
| 57 Keyword.RETURN, | |
| 58 Keyword.SWITCH, | |
| 59 Keyword.THROW, | |
| 60 Keyword.TRY, | |
| 61 Keyword.VAR, | |
| 62 Keyword.VOID, | |
| 63 Keyword.WHILE | |
| 64 ]); | |
| 65 } | |
| 66 | |
| 67 @override | |
| 68 visitClassDeclaration(ClassDeclaration node) { | |
| 69 // Don't suggest class name | |
| 70 if (entity == node.name) { | |
| 71 return; | |
| 72 } | |
| 73 if (entity == node.rightBracket || entity is ClassMember) { | |
| 74 _addSuggestions([ | |
| 75 Keyword.CONST, | |
| 76 Keyword.DYNAMIC, | |
| 77 Keyword.FACTORY, | |
| 78 Keyword.FINAL, | |
| 79 Keyword.GET, | |
| 80 Keyword.OPERATOR, | |
| 81 Keyword.SET, | |
| 82 Keyword.STATIC, | |
| 83 Keyword.VAR, | |
| 84 Keyword.VOID | |
| 85 ]); | |
| 86 return; | |
| 87 } | |
| 88 _addClassDeclarationKeywords(node); | |
| 89 } | |
| 90 | |
| 91 @override | |
| 92 visitCompilationUnit(CompilationUnit node) { | |
| 93 var previousMember = null; | |
| 94 for (var member in node.childEntities) { | |
| 95 if (entity == member) { | |
| 96 break; | |
| 97 } | |
| 98 previousMember = member; | |
| 99 } | |
| 100 if (previousMember is ClassDeclaration) { | |
| 101 if (previousMember.leftBracket == null || | |
| 102 previousMember.leftBracket.isSynthetic) { | |
| 103 // If the prior member is an unfinished class declaration | |
| 104 // then the user is probably finishing that | |
| 105 _addClassDeclarationKeywords(previousMember); | |
| 106 return; | |
| 107 } | |
| 108 } | |
| 109 if (previousMember == null || previousMember is Directive) { | |
| 110 if (previousMember == null && | |
| 111 !node.directives.any((d) => d is LibraryDirective)) { | |
| 112 _addSuggestions([Keyword.LIBRARY], DART_RELEVANCE_HIGH); | |
| 113 } | |
| 114 _addSuggestions( | |
| 115 [Keyword.EXPORT, Keyword.IMPORT, Keyword.PART], DART_RELEVANCE_HIGH); | |
| 116 } | |
| 117 if (entity == null || entity is Declaration) { | |
| 118 _addSuggestions([ | |
| 119 Keyword.ABSTRACT, | |
| 120 Keyword.CLASS, | |
| 121 Keyword.CONST, | |
| 122 Keyword.DYNAMIC, | |
| 123 Keyword.FINAL, | |
| 124 Keyword.TYPEDEF, | |
| 125 Keyword.VAR, | |
| 126 Keyword.VOID | |
| 127 ], DART_RELEVANCE_HIGH); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 void _addClassDeclarationKeywords(ClassDeclaration node) { | |
| 132 // Very simplistic suggestion because analyzer will warn if | |
| 133 // the extends / with / implements keywords are out of order | |
| 134 if (node.extendsClause == null) { | |
| 135 _addSuggestion(Keyword.EXTENDS, DART_RELEVANCE_HIGH); | |
| 136 } else if (node.withClause == null) { | |
| 137 _addSuggestion(Keyword.WITH, DART_RELEVANCE_HIGH); | |
| 138 } | |
| 139 if (node.implementsClause == null) { | |
| 140 _addSuggestion(Keyword.IMPLEMENTS, DART_RELEVANCE_HIGH); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 void _addSuggestion(Keyword keyword, | |
| 145 [int relevance = DART_RELEVANCE_DEFAULT]) { | |
| 146 String completion = keyword.syntax; | |
| 147 request.addSuggestion(new CompletionSuggestion( | |
| 148 CompletionSuggestionKind.KEYWORD, relevance, completion, | |
| 149 completion.length, 0, false, false)); | |
| 150 } | |
| 151 | |
| 152 void _addSuggestions(List<Keyword> keywords, | |
| 153 [int relevance = DART_RELEVANCE_KEYWORD]) { | |
| 154 keywords.forEach((Keyword keyword) { | |
| 155 _addSuggestion(keyword, relevance); | |
| 156 }); | |
| 157 } | |
| 158 | |
| 159 bool _isInClassMemberBody(AstNode node) { | |
| 160 while (true) { | |
| 161 AstNode body = node.getAncestor((n) => n is FunctionBody); | |
| 162 if (body == null) { | |
| 163 return false; | |
| 164 } | |
| 165 AstNode parent = body.parent; | |
| 166 if (parent is ConstructorDeclaration || parent is MethodDeclaration) { | |
| 167 return true; | |
| 168 } | |
| 169 node = parent; | |
| 170 } | |
| 171 } | |
| 172 } | |
| OLD | NEW |