| OLD | NEW |
| 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:async'; | 5 import 'dart:async'; |
| 6 import 'dart:collection'; | 6 import 'dart:collection'; |
| 7 | 7 |
| 8 import 'package:analyzer/dart/ast/ast.dart'; | 8 import 'package:analyzer/dart/ast/ast.dart'; |
| 9 import 'package:analyzer/dart/element/element.dart'; | 9 import 'package:analyzer/dart/element/element.dart'; |
| 10 import 'package:analyzer/dart/element/type.dart'; | 10 import 'package:analyzer/dart/element/type.dart'; |
| 11 import 'package:analyzer/file_system/file_system.dart'; | 11 import 'package:analyzer/file_system/file_system.dart'; |
| 12 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element; | 12 import 'package:analyzer_plugin/protocol/protocol_common.dart' hide Element; |
| 13 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart'
; | 13 import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart'
; |
| 14 import 'package:analyzer_plugin/src/utilities/completion/suggestion_builder.dart
'; | 14 import 'package:analyzer_plugin/src/utilities/completion/suggestion_builder.dart
'; |
| 15 import 'package:analyzer_plugin/src/utilities/visitors/local_declaration_visitor
.dart'; | 15 import 'package:analyzer_plugin/src/utilities/visitors/local_declaration_visitor
.dart'; |
| 16 import 'package:analyzer_plugin/utilities/completion/completion_core.dart'; | 16 import 'package:analyzer_plugin/utilities/completion/completion_core.dart'; |
| 17 import 'package:analyzer_plugin/utilities/completion/relevance.dart'; | 17 import 'package:analyzer_plugin/utilities/completion/relevance.dart'; |
| 18 import 'package:analyzer_plugin/utilities/completion/suggestion_builder.dart'; | 18 import 'package:analyzer_plugin/utilities/completion/suggestion_builder.dart'; |
| 19 | 19 |
| 20 /** | 20 /** |
| 21 * A completion contributor that will generate suggestions for instance | 21 * A completion contributor that will generate suggestions for instance |
| 22 * invocations and accesses. | 22 * invocations and accesses. |
| 23 */ | 23 */ |
| 24 class TypeMemberContributor implements CompletionContributor { | 24 class TypeMemberContributor implements CompletionContributor { |
| 25 /** | 25 /** |
| 26 * Clients should not overload this function. | 26 * Plugin contributors should primarily overload this function. |
| 27 * Should more parameters be needed for autocompletion needs, the |
| 28 * overloaded function should define those parameters and |
| 29 * call on `computeSuggestionsWithEntryPoint`. |
| 27 */ | 30 */ |
| 28 Future<Null> computeSuggestionsWithEntryPoint(CompletionRequest request, | 31 @override |
| 29 CompletionCollector collector, AstNode entryPoint) async { | 32 Future<Null> computeSuggestions( |
| 33 DartCompletionRequest request, CompletionCollector collector) async { |
| 30 LibraryElement containingLibrary = request.result.libraryElement; | 34 LibraryElement containingLibrary = request.result.libraryElement; |
| 31 // Gracefully degrade if the library element is not resolved | 35 // Gracefully degrade if the library element is not resolved |
| 32 // e.g. detached part file or source change | 36 // e.g. detached part file or source change |
| 33 if (containingLibrary == null) { | 37 if (containingLibrary == null) { |
| 34 return; | 38 return; |
| 35 } | 39 } |
| 36 | 40 |
| 37 // Recompute the target since resolution may have changed it | 41 // Recompute the target since resolution may have changed it |
| 38 Expression expression = _computeDotTarget(request, entryPoint); | 42 Expression expression = _computeDotTarget(request, null); |
| 39 if (expression == null || expression.isSynthetic) { | 43 if (expression == null || expression.isSynthetic) { |
| 40 return; | 44 return; |
| 41 } | 45 } |
| 42 _computeSuggestions(request, collector, containingLibrary, expression); | 46 _computeSuggestions(request, collector, containingLibrary, expression); |
| 43 } | 47 } |
| 44 | 48 |
| 45 /** | 49 /** |
| 46 * Plugin contributors should primarily overload this function. | 50 * Clients should not overload this function. |
| 47 * Should more parameters be needed for autocompletion needs, the | |
| 48 * overloaded function should define those parameters and | |
| 49 * call on `computeSuggestionsWithEntryPoint`. | |
| 50 */ | 51 */ |
| 51 @override | 52 Future<Null> computeSuggestionsWithEntryPoint(DartCompletionRequest request, |
| 52 Future<Null> computeSuggestions( | 53 CompletionCollector collector, AstNode entryPoint) async { |
| 53 CompletionRequest request, CompletionCollector collector) async { | |
| 54 LibraryElement containingLibrary = request.result.libraryElement; | 54 LibraryElement containingLibrary = request.result.libraryElement; |
| 55 // Gracefully degrade if the library element is not resolved | 55 // Gracefully degrade if the library element is not resolved |
| 56 // e.g. detached part file or source change | 56 // e.g. detached part file or source change |
| 57 if (containingLibrary == null) { | 57 if (containingLibrary == null) { |
| 58 return; | 58 return; |
| 59 } | 59 } |
| 60 | 60 |
| 61 // Recompute the target since resolution may have changed it | 61 // Recompute the target since resolution may have changed it |
| 62 Expression expression = _computeDotTarget(request, null); | 62 Expression expression = _computeDotTarget(request, entryPoint); |
| 63 if (expression == null || expression.isSynthetic) { | 63 if (expression == null || expression.isSynthetic) { |
| 64 return; | 64 return; |
| 65 } | 65 } |
| 66 _computeSuggestions(request, collector, containingLibrary, expression); | 66 _computeSuggestions(request, collector, containingLibrary, expression); |
| 67 } | 67 } |
| 68 | 68 |
| 69 /** |
| 70 * Update the completion [target] and [dotTarget] based on the given [unit]. |
| 71 */ |
| 72 Expression _computeDotTarget( |
| 73 DartCompletionRequest request, AstNode entryPoint) { |
| 74 CompletionTarget target = new CompletionTarget.forOffset( |
| 75 request.result.unit, request.offset, |
| 76 entryPoint: entryPoint); |
| 77 AstNode node = target.containingNode; |
| 78 if (node is MethodInvocation) { |
| 79 if (identical(node.methodName, target.entity)) { |
| 80 return node.realTarget; |
| 81 } else if (node.isCascaded && node.operator.offset + 1 == target.offset) { |
| 82 return node.realTarget; |
| 83 } |
| 84 } |
| 85 if (node is PropertyAccess) { |
| 86 if (identical(node.propertyName, target.entity)) { |
| 87 return node.realTarget; |
| 88 } else if (node.isCascaded && node.operator.offset + 1 == target.offset) { |
| 89 return node.realTarget; |
| 90 } |
| 91 } |
| 92 if (node is PrefixedIdentifier) { |
| 93 if (identical(node.identifier, target.entity)) { |
| 94 return node.prefix; |
| 95 } |
| 96 } |
| 97 return null; |
| 98 } |
| 99 |
| 69 void _computeSuggestions( | 100 void _computeSuggestions( |
| 70 CompletionRequest request, | 101 DartCompletionRequest request, |
| 71 CompletionCollector collector, | 102 CompletionCollector collector, |
| 72 LibraryElement containingLibrary, | 103 LibraryElement containingLibrary, |
| 73 Expression expression) { | 104 Expression expression) { |
| 74 if (expression is Identifier) { | 105 if (expression is Identifier) { |
| 75 Element element = expression.bestElement; | 106 Element element = expression.bestElement; |
| 76 if (element is ClassElement) { | 107 if (element is ClassElement) { |
| 77 // Suggestions provided by StaticMemberContributor | 108 // Suggestions provided by StaticMemberContributor |
| 78 return; | 109 return; |
| 79 } | 110 } |
| 80 if (element is PrefixElement) { | 111 if (element is PrefixElement) { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 type = request.result.typeProvider.objectType; | 160 type = request.result.typeProvider.objectType; |
| 130 } | 161 } |
| 131 | 162 |
| 132 // Build the suggestions | 163 // Build the suggestions |
| 133 if (type is InterfaceType) { | 164 if (type is InterfaceType) { |
| 134 _SuggestionBuilder builder = new _SuggestionBuilder( | 165 _SuggestionBuilder builder = new _SuggestionBuilder( |
| 135 request.resourceProvider, collector, containingLibrary); | 166 request.resourceProvider, collector, containingLibrary); |
| 136 builder.buildSuggestions(type, containingMethodName); | 167 builder.buildSuggestions(type, containingMethodName); |
| 137 } | 168 } |
| 138 } | 169 } |
| 139 | |
| 140 /** | |
| 141 * Update the completion [target] and [dotTarget] based on the given [unit]. | |
| 142 */ | |
| 143 Expression _computeDotTarget(CompletionRequest request, AstNode entryPoint) { | |
| 144 CompletionTarget target = new CompletionTarget.forOffset( | |
| 145 request.result.unit, request.offset, | |
| 146 entryPoint: entryPoint); | |
| 147 AstNode node = target.containingNode; | |
| 148 if (node is MethodInvocation) { | |
| 149 if (identical(node.methodName, target.entity)) { | |
| 150 return node.realTarget; | |
| 151 } else if (node.isCascaded && node.operator.offset + 1 == target.offset) { | |
| 152 return node.realTarget; | |
| 153 } | |
| 154 } | |
| 155 if (node is PropertyAccess) { | |
| 156 if (identical(node.propertyName, target.entity)) { | |
| 157 return node.realTarget; | |
| 158 } else if (node.isCascaded && node.operator.offset + 1 == target.offset) { | |
| 159 return node.realTarget; | |
| 160 } | |
| 161 } | |
| 162 if (node is PrefixedIdentifier) { | |
| 163 if (identical(node.identifier, target.entity)) { | |
| 164 return node.prefix; | |
| 165 } | |
| 166 } | |
| 167 return null; | |
| 168 } | |
| 169 } | 170 } |
| 170 | 171 |
| 171 /** | 172 /** |
| 172 * An [AstVisitor] which looks for a declaration with the given name | 173 * An [AstVisitor] which looks for a declaration with the given name |
| 173 * and if found, tries to determine a type for that declaration. | 174 * and if found, tries to determine a type for that declaration. |
| 174 */ | 175 */ |
| 175 class _LocalBestTypeVisitor extends LocalDeclarationVisitor { | 176 class _LocalBestTypeVisitor extends LocalDeclarationVisitor { |
| 176 /** | 177 /** |
| 177 * The name for the declaration to be found. | 178 * The name for the declaration to be found. |
| 178 */ | 179 */ |
| (...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 489 // in the reverse order. | 490 // in the reverse order. |
| 490 typesToVisit.addAll(nextType.interfaces); | 491 typesToVisit.addAll(nextType.interfaces); |
| 491 if (nextType.superclass != null) { | 492 if (nextType.superclass != null) { |
| 492 typesToVisit.add(nextType.superclass); | 493 typesToVisit.add(nextType.superclass); |
| 493 } | 494 } |
| 494 typesToVisit.addAll(nextType.mixins); | 495 typesToVisit.addAll(nextType.mixins); |
| 495 } | 496 } |
| 496 return result; | 497 return result; |
| 497 } | 498 } |
| 498 } | 499 } |
| OLD | NEW |