mirror of
https://github.com/dart-lang/sdk
synced 2024-11-02 12:24:24 +00:00
Change to accommade Angular plugin and finalize removal of dependency to analysis_server
BUG= R=brianwilkerson@google.com, mfairhurst@google.com Review-Url: https://codereview.chromium.org/2934133002 .
This commit is contained in:
parent
e9eeb1a070
commit
e57d9b608f
5 changed files with 167 additions and 16 deletions
|
@ -65,6 +65,12 @@ class CompletionCollectorImpl implements CompletionCollector {
|
|||
void addSuggestion(CompletionSuggestion suggestion) {
|
||||
suggestions.add(suggestion);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get offsetIsSet => offset != null;
|
||||
|
||||
@override
|
||||
int get suggestionsLength => suggestions.length;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright (c) 2017, 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:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/src/dart/ast/token.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
|
||||
|
||||
/**
|
||||
* Utility class for computing the code completion replacement range
|
||||
*/
|
||||
class ReplacementRange {
|
||||
int offset;
|
||||
int length;
|
||||
|
||||
ReplacementRange(this.offset, this.length);
|
||||
|
||||
factory ReplacementRange.compute(int requestOffset, CompletionTarget target) {
|
||||
bool isKeywordOrIdentifier(Token token) =>
|
||||
token.type.isKeyword || token.type == TokenType.IDENTIFIER;
|
||||
|
||||
//TODO(danrubel) Ideally this needs to be pushed down into the contributors
|
||||
// but that implies that each suggestion can have a different
|
||||
// replacement offsent/length which would mean an API change
|
||||
|
||||
var entity = target.entity;
|
||||
Token token = entity is AstNode ? entity.beginToken : entity;
|
||||
if (token != null && requestOffset < token.offset) {
|
||||
token = token.previous;
|
||||
}
|
||||
if (token != null) {
|
||||
if (requestOffset == token.offset && !isKeywordOrIdentifier(token)) {
|
||||
// If the insertion point is at the beginning of the current token
|
||||
// and the current token is not an identifier
|
||||
// then check the previous token to see if it should be replaced
|
||||
token = token.previous;
|
||||
}
|
||||
if (token != null && isKeywordOrIdentifier(token)) {
|
||||
if (token.offset <= requestOffset && requestOffset <= token.end) {
|
||||
// Replacement range for typical identifier completion
|
||||
return new ReplacementRange(token.offset, token.length);
|
||||
}
|
||||
}
|
||||
if (token is StringToken) {
|
||||
SimpleStringLiteral uri =
|
||||
astFactory.simpleStringLiteral(token, token.lexeme);
|
||||
Keyword keyword = token.previous?.keyword;
|
||||
if (keyword == Keyword.IMPORT ||
|
||||
keyword == Keyword.EXPORT ||
|
||||
keyword == Keyword.PART) {
|
||||
int start = uri.contentsOffset;
|
||||
var end = uri.contentsEnd;
|
||||
if (start <= requestOffset && requestOffset <= end) {
|
||||
// Replacement range for import URI
|
||||
return new ReplacementRange(start, end - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new ReplacementRange(requestOffset, 0);
|
||||
}
|
||||
}
|
|
@ -45,6 +45,17 @@ abstract class CompletionCollector {
|
|||
*/
|
||||
void set offset(int offset);
|
||||
|
||||
/**
|
||||
* Indicates if the collector's offset has been set (and ultimately the
|
||||
* length too).
|
||||
*/
|
||||
bool get offsetIsSet;
|
||||
|
||||
/**
|
||||
* Returns length of suggestions currently held.
|
||||
*/
|
||||
int get suggestionsLength;
|
||||
|
||||
/**
|
||||
* Record the given completion [suggestion].
|
||||
*/
|
||||
|
@ -104,6 +115,9 @@ class CompletionGenerator {
|
|||
} on AbortCompletion {
|
||||
return new GeneratorResult(null, notifications);
|
||||
}
|
||||
collector.offset ??= request.offset;
|
||||
collector.length ??= 0;
|
||||
|
||||
CompletionGetSuggestionsResult result = new CompletionGetSuggestionsResult(
|
||||
collector.offset, collector.length, collector.suggestions);
|
||||
return new GeneratorResult(result, notifications);
|
||||
|
|
|
@ -17,6 +17,9 @@ import 'package:analyzer_plugin/utilities/completion/completion_core.dart';
|
|||
|
||||
/**
|
||||
* A contributor for calculating suggestions for inherited references.
|
||||
*
|
||||
* Plugin developers should extend this function and primarily
|
||||
* overload `computeSuggestions` (if needed).
|
||||
*/
|
||||
class InheritedReferenceContributor extends Object
|
||||
with ElementSuggestionBuilder
|
||||
|
@ -30,6 +33,12 @@ class InheritedReferenceContributor extends Object
|
|||
@override
|
||||
ResourceProvider resourceProvider;
|
||||
|
||||
/**
|
||||
* Plugin contributors should primarily overload this function.
|
||||
* Should more parameters be needed for autocompletion needs, the
|
||||
* overloaded function should define those parameters and
|
||||
* call on `computeSuggestionsForClass`.
|
||||
*/
|
||||
@override
|
||||
Future<Null> computeSuggestions(
|
||||
CompletionRequest request, CompletionCollector collector) async {
|
||||
|
@ -44,12 +53,39 @@ class InheritedReferenceContributor extends Object
|
|||
return;
|
||||
}
|
||||
containingLibrary = request.result.libraryElement;
|
||||
_computeSuggestionsForClass2(
|
||||
collector,
|
||||
target,
|
||||
resolutionMap.elementDeclaredByClassDeclaration(classDecl),
|
||||
request,
|
||||
optype);
|
||||
_computeSuggestionsForClass2(collector, target,
|
||||
resolutionMap.elementDeclaredByClassDeclaration(classDecl), optype);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients should not overload this function.
|
||||
*/
|
||||
Future<Null> computeSuggestionsForClass(
|
||||
CompletionRequest request,
|
||||
CompletionCollector collector,
|
||||
ClassElement classElement, {
|
||||
AstNode entryPoint,
|
||||
bool skipChildClass,
|
||||
CompletionTarget target,
|
||||
OpType optype,
|
||||
}) async {
|
||||
target ??= new CompletionTarget.forOffset(
|
||||
request.result.unit, request.offset,
|
||||
entryPoint: entryPoint);
|
||||
optype ??= new OpType.forCompletion(target, request.offset);
|
||||
if (!optype.includeIdentifiers) {
|
||||
return;
|
||||
}
|
||||
if (classElement == null) {
|
||||
ClassDeclaration classDecl = _enclosingClass(target);
|
||||
if (classDecl == null || classDecl.element == null) {
|
||||
return;
|
||||
}
|
||||
classElement = resolutionMap.elementDeclaredByClassDeclaration(classDecl);
|
||||
}
|
||||
containingLibrary = request.result.libraryElement;
|
||||
_computeSuggestionsForClass2(collector, target, classElement, optype,
|
||||
skipChildClass: skipChildClass);
|
||||
}
|
||||
|
||||
_addSuggestionsForType(InterfaceType type, OpType optype,
|
||||
|
@ -82,12 +118,8 @@ class InheritedReferenceContributor extends Object
|
|||
}
|
||||
}
|
||||
|
||||
void _computeSuggestionsForClass2(
|
||||
CompletionCollector collector,
|
||||
CompletionTarget target,
|
||||
ClassElement classElement,
|
||||
CompletionRequest request,
|
||||
OpType optype,
|
||||
void _computeSuggestionsForClass2(CompletionCollector collector,
|
||||
CompletionTarget target, ClassElement classElement, OpType optype,
|
||||
{bool skipChildClass: true}) {
|
||||
bool isFunctionalArgument = target.isFunctionalArgument();
|
||||
kind = isFunctionalArgument
|
||||
|
|
|
@ -22,6 +22,32 @@ import 'package:analyzer_plugin/utilities/completion/suggestion_builder.dart';
|
|||
* invocations and accesses.
|
||||
*/
|
||||
class TypeMemberContributor implements CompletionContributor {
|
||||
/**
|
||||
* Clients should not overload this function.
|
||||
*/
|
||||
Future<Null> computeSuggestionsWithEntryPoint(CompletionRequest request,
|
||||
CompletionCollector collector, AstNode entryPoint) async {
|
||||
LibraryElement containingLibrary = request.result.libraryElement;
|
||||
// Gracefully degrade if the library element is not resolved
|
||||
// e.g. detached part file or source change
|
||||
if (containingLibrary == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Recompute the target since resolution may have changed it
|
||||
Expression expression = _computeDotTarget(request, entryPoint);
|
||||
if (expression == null || expression.isSynthetic) {
|
||||
return;
|
||||
}
|
||||
_computeSuggestions(request, collector, containingLibrary, expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin contributors should primarily overload this function.
|
||||
* Should more parameters be needed for autocompletion needs, the
|
||||
* overloaded function should define those parameters and
|
||||
* call on `computeSuggestionsWithEntryPoint`.
|
||||
*/
|
||||
@override
|
||||
Future<Null> computeSuggestions(
|
||||
CompletionRequest request, CompletionCollector collector) async {
|
||||
|
@ -33,10 +59,18 @@ class TypeMemberContributor implements CompletionContributor {
|
|||
}
|
||||
|
||||
// Recompute the target since resolution may have changed it
|
||||
Expression expression = _computeDotTarget(request);
|
||||
Expression expression = _computeDotTarget(request, null);
|
||||
if (expression == null || expression.isSynthetic) {
|
||||
return;
|
||||
}
|
||||
_computeSuggestions(request, collector, containingLibrary, expression);
|
||||
}
|
||||
|
||||
void _computeSuggestions(
|
||||
CompletionRequest request,
|
||||
CompletionCollector collector,
|
||||
LibraryElement containingLibrary,
|
||||
Expression expression) {
|
||||
if (expression is Identifier) {
|
||||
Element element = expression.bestElement;
|
||||
if (element is ClassElement) {
|
||||
|
@ -106,9 +140,10 @@ class TypeMemberContributor implements CompletionContributor {
|
|||
/**
|
||||
* Update the completion [target] and [dotTarget] based on the given [unit].
|
||||
*/
|
||||
Expression _computeDotTarget(CompletionRequest request) {
|
||||
CompletionTarget target =
|
||||
new CompletionTarget.forOffset(request.result.unit, request.offset);
|
||||
Expression _computeDotTarget(CompletionRequest request, AstNode entryPoint) {
|
||||
CompletionTarget target = new CompletionTarget.forOffset(
|
||||
request.result.unit, request.offset,
|
||||
entryPoint: entryPoint);
|
||||
AstNode node = target.containingNode;
|
||||
if (node is MethodInvocation) {
|
||||
if (identical(node.methodName, target.entity)) {
|
||||
|
|
Loading…
Reference in a new issue