mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 14:53:37 +00:00
Reorganize InheritedRefenenceContributor to serve angular completion
Take the parts that I would have simply copied and pasted them into my own code, and create new public & private methods to serve the new organization. Add an option to get the current class's accessors/methods along with the inherited ones, because that's what I want. Make opType a public member of DartCompletionRequest Its used so heavily by so many of the autocomplete targets, it really doesn't need to be hidden on the Impl. Besides, I want to use InheritedReferenceContributor, which upcasts the DartCompletionRequest into the Impl in order to grab this field -- but for a large number of reasons I can't really use DartCompletionRequestImpl. Therefore I need my own class to implement DartCompletionRequest and therefore my code will only work with InheritedReferenceContributor if it doesn't have to look outside the interface for this information. Change to enable the angular analysis project to do autocomplete We don't have CompilationUnits, but we do have dart ASTs, and we want to find the completion target with the same algorithm. The CompletionTarget class's functionality doesn't depend on its member compilationUnit not being null, so that isn't a problem for us. However, in `forOffset()`, we cannot pass in a null unit, even though its only used to set the `compilationUnit` member and otherwise only used as an `AstNode` which we have. So rather than using `compilationUnit` as the entry point of the algorithm, add a new `AstNode` parameter to represent the entry point, and when its null simply use the value of `compilationUnit`. BUG= R=brianwilkerson@google.com Review-Url: https://codereview.chromium.org/2565633002 .
This commit is contained in:
parent
53e93e8b05
commit
d8c9645c26
|
@ -99,6 +99,12 @@ abstract class DartCompletionRequest extends CompletionRequest {
|
|||
*/
|
||||
DartType get objectType;
|
||||
|
||||
/**
|
||||
* The [OpType] which describes which types of suggestions would fit the
|
||||
* request.
|
||||
*/
|
||||
OpType get opType;
|
||||
|
||||
/**
|
||||
* Return the [SourceFactory] of the request.
|
||||
*/
|
||||
|
|
|
@ -137,16 +137,20 @@ class CompletionTarget {
|
|||
/**
|
||||
* Compute the appropriate [CompletionTarget] for the given [offset] within
|
||||
* the [compilationUnit].
|
||||
*
|
||||
* Optionally, start the search from within [entryPoint] instead of using
|
||||
* the [compilationUnit], which is useful for analyzing ASTs that have no
|
||||
* [compilationUnit] such as dart expressions within angular templates.
|
||||
*/
|
||||
factory CompletionTarget.forOffset(
|
||||
CompilationUnit compilationUnit, int offset) {
|
||||
CompilationUnit compilationUnit, int offset, {AstNode entryPoint}) {
|
||||
// The precise algorithm is as follows. We perform a depth-first search of
|
||||
// all edges in the parse tree (both those that point to AST nodes and
|
||||
// those that point to tokens), visiting parents before children. The
|
||||
// first edge which points to an entity satisfying either _isCandidateToken
|
||||
// or _isCandidateNode is the completion target. If no edge is found that
|
||||
// satisfies these two predicates, then we set the completion target entity
|
||||
// to null and the containingNode to the compilationUnit.
|
||||
// to null and the containingNode to the entryPoint.
|
||||
//
|
||||
// Note that if a token is not a candidate target, then none of the tokens
|
||||
// that precede it are candidate targets either. Therefore any entity
|
||||
|
@ -154,7 +158,8 @@ class CompletionTarget {
|
|||
// prune the search to the point where no recursion is necessary; at each
|
||||
// step in the process we know exactly which child node we need to proceed
|
||||
// to.
|
||||
AstNode containingNode = compilationUnit;
|
||||
entryPoint ??= compilationUnit;
|
||||
AstNode containingNode = entryPoint;
|
||||
outerLoop: while (true) {
|
||||
if (containingNode is Comment) {
|
||||
// Comments are handled specially: we descend into any CommentReference
|
||||
|
@ -232,13 +237,13 @@ class CompletionTarget {
|
|||
// the first time through the outer loop (since we only jump to the start
|
||||
// of the outer loop after determining that the completion target is
|
||||
// inside an entity). We can check that assumption by verifying that
|
||||
// containingNode is still the compilationUnit.
|
||||
assert(identical(containingNode, compilationUnit));
|
||||
// containingNode is still the entryPoint.
|
||||
assert(identical(containingNode, entryPoint));
|
||||
|
||||
// Since no completion target was found, we set the completion target
|
||||
// entity to null and use the compilationUnit as the parent.
|
||||
// entity to null and use the entryPoint as the parent.
|
||||
return new CompletionTarget._(
|
||||
compilationUnit, offset, compilationUnit, null, false);
|
||||
compilationUnit, offset, entryPoint, null, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -192,12 +192,7 @@ class DartCompletionRequestImpl implements DartCompletionRequest {
|
|||
|
||||
@override
|
||||
bool get includeIdentifiers {
|
||||
opType; // <<< ensure _opType is initialized
|
||||
return !_opType.isPrefixed &&
|
||||
(_opType.includeReturnValueSuggestions ||
|
||||
_opType.includeTypeNameSuggestions ||
|
||||
_opType.includeVoidReturnSuggestions ||
|
||||
_opType.includeConstructorSuggestions);
|
||||
return opType.includeIdentifiers;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -62,37 +62,54 @@ class InheritedReferenceContributor extends DartCompletionContributor
|
|||
if (!request.includeIdentifiers) {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
ClassDeclaration classDecl = _enclosingClass(request.target);
|
||||
if (classDecl == null || classDecl.element == null) {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
|
||||
containingLibrary = request.libraryElement;
|
||||
return _computeSuggestionsForClass2(resolutionMap
|
||||
.elementDeclaredByClassDeclaration(classDecl), request);
|
||||
}
|
||||
|
||||
List<CompletionSuggestion> _computeSuggestionsForClass2(
|
||||
ClassElement classElement, DartCompletionRequest request,
|
||||
{bool skipChildClass: true}) {
|
||||
bool isFunctionalArgument = request.target.isFunctionalArgument();
|
||||
kind = isFunctionalArgument
|
||||
? CompletionSuggestionKind.IDENTIFIER
|
||||
: CompletionSuggestionKind.INVOCATION;
|
||||
OpType optype = (request as DartCompletionRequestImpl).opType;
|
||||
for (InterfaceType type in resolutionMap
|
||||
.elementDeclaredByClassDeclaration(classDecl)
|
||||
.allSupertypes) {
|
||||
if (!isFunctionalArgument) {
|
||||
for (PropertyAccessorElement elem in type.accessors) {
|
||||
if (elem.isGetter) {
|
||||
if (optype.includeReturnValueSuggestions) {
|
||||
addSuggestion(elem);
|
||||
}
|
||||
} else {
|
||||
if (optype.includeVoidReturnSuggestions) {
|
||||
addSuggestion(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (MethodElement elem in type.methods) {
|
||||
if (elem.returnType == null) {
|
||||
addSuggestion(elem);
|
||||
} else if (!elem.returnType.isVoid) {
|
||||
OpType optype = request.opType;
|
||||
|
||||
if (!skipChildClass) {
|
||||
_addSuggestionsForType(classElement.type, optype,
|
||||
isFunctionalArgument: isFunctionalArgument);
|
||||
}
|
||||
|
||||
for (InterfaceType type in classElement.allSupertypes) {
|
||||
_addSuggestionsForType(type, optype,
|
||||
isFunctionalArgument: isFunctionalArgument);
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
List<CompletionSuggestion> computeSuggestionsForClass(
|
||||
ClassElement classElement, DartCompletionRequest request,
|
||||
{bool skipChildClass: true}) {
|
||||
if (!request.includeIdentifiers) {
|
||||
return EMPTY_LIST;
|
||||
}
|
||||
containingLibrary = request.libraryElement;
|
||||
|
||||
return _computeSuggestionsForClass2(classElement, request,
|
||||
skipChildClass: skipChildClass);
|
||||
}
|
||||
|
||||
_addSuggestionsForType(InterfaceType type, OpType optype,
|
||||
{bool isFunctionalArgument: false}) {
|
||||
if (!isFunctionalArgument) {
|
||||
for (PropertyAccessorElement elem in type.accessors) {
|
||||
if (elem.isGetter) {
|
||||
if (optype.includeReturnValueSuggestions) {
|
||||
addSuggestion(elem);
|
||||
}
|
||||
|
@ -103,6 +120,18 @@ class InheritedReferenceContributor extends DartCompletionContributor
|
|||
}
|
||||
}
|
||||
}
|
||||
return suggestions;
|
||||
for (MethodElement elem in type.methods) {
|
||||
if (elem.returnType == null) {
|
||||
addSuggestion(elem);
|
||||
} else if (!elem.returnType.isVoid) {
|
||||
if (optype.includeReturnValueSuggestions) {
|
||||
addSuggestion(elem);
|
||||
}
|
||||
} else {
|
||||
if (optype.includeVoidReturnSuggestions) {
|
||||
addSuggestion(elem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,17 @@ class OpType {
|
|||
!includeReturnValueSuggestions &&
|
||||
!includeVoidReturnSuggestions;
|
||||
|
||||
/**
|
||||
* Return `true` if free standing identifiers should be suggested
|
||||
*/
|
||||
bool get includeIdentifiers {
|
||||
return !isPrefixed &&
|
||||
(includeReturnValueSuggestions ||
|
||||
includeTypeNameSuggestions ||
|
||||
includeVoidReturnSuggestions ||
|
||||
includeConstructorSuggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether only type names should be suggested
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue