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:
Max Kim 2017-06-13 16:31:29 -07:00
parent e9eeb1a070
commit e57d9b608f
5 changed files with 167 additions and 16 deletions

View file

@ -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;
}
/**

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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

View file

@ -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)) {