Modify the override_contributor.dart to provide the completions even when no class member characters have been typed.
Change-Id: I03164bcb0761faf7634ec219a1b1cc87dc568fa9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/144493 Commit-Queue: Jaime Wren <jwren@google.com> Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
68e77baf59
commit
f7d14e49c2
@@ -15,6 +15,7 @@ import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/dart/element/nullability_suffix.dart';
|
||||
import 'package:analyzer/dart/element/type.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
|
||||
import 'package:analyzer_plugin/src/utilities/completion/completion_target.dart';
|
||||
import 'package:analyzer_plugin/utilities/change_builder/change_builder_dart.dart';
|
||||
@@ -26,14 +27,19 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
@override
|
||||
Future<List<CompletionSuggestion>> computeSuggestions(
|
||||
DartCompletionRequest request, SuggestionBuilder builder) async {
|
||||
var targetId = _getTargetId(request.target);
|
||||
if (targetId == null) {
|
||||
return const <CompletionSuggestion>[];
|
||||
}
|
||||
var classDecl = targetId.thisOrAncestorOfType<ClassOrMixinDeclaration>();
|
||||
var target = request.target;
|
||||
var containingNode = target.containingNode;
|
||||
var classDecl =
|
||||
containingNode.thisOrAncestorOfType<ClassOrMixinDeclaration>();
|
||||
if (classDecl == null) {
|
||||
return const <CompletionSuggestion>[];
|
||||
}
|
||||
if (_inClassMemberBody(containingNode)) {
|
||||
return const <CompletionSuggestion>[];
|
||||
}
|
||||
|
||||
var sourceRange = _getTargetSourceRange(target);
|
||||
sourceRange ??= range.startOffsetEndOffset(request.offset, 0);
|
||||
|
||||
var inheritance = InheritanceManager3();
|
||||
|
||||
@@ -53,7 +59,7 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
if (element.returnType != null) {
|
||||
var invokeSuper = interface.isSuperImplemented(name);
|
||||
var suggestion =
|
||||
await _buildSuggestion(request, targetId, element, invokeSuper);
|
||||
await _buildSuggestion(request, sourceRange, element, invokeSuper);
|
||||
if (suggestion != null) {
|
||||
suggestions.add(suggestion);
|
||||
}
|
||||
@@ -62,17 +68,17 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
/// Build a suggestion to replace [targetId] in the given [request] with an
|
||||
/// Build a suggestion to replace [sourceRange] in the given [request] with an
|
||||
/// override of the given [element].
|
||||
Future<CompletionSuggestion> _buildSuggestion(
|
||||
DartCompletionRequest request,
|
||||
SimpleIdentifier targetId,
|
||||
SourceRange sourceRange,
|
||||
ExecutableElement element,
|
||||
bool invokeSuper) async {
|
||||
var displayTextBuffer = StringBuffer();
|
||||
var builder = DartChangeBuilder(request.result.session);
|
||||
await builder.addFileEdit(request.result.path, (builder) {
|
||||
builder.addReplacement(range.node(targetId), (builder) {
|
||||
builder.addReplacement(sourceRange, (builder) {
|
||||
builder.writeOverride(
|
||||
element,
|
||||
displayTextBuffer: displayTextBuffer,
|
||||
@@ -102,7 +108,7 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
if (selectionRange == null) {
|
||||
return null;
|
||||
}
|
||||
var offsetDelta = targetId.offset + replacement.indexOf(completion);
|
||||
var offsetDelta = sourceRange.offset + replacement.indexOf(completion);
|
||||
var displayText =
|
||||
displayTextBuffer.isNotEmpty ? displayTextBuffer.toString() : null;
|
||||
var suggestion = CompletionSuggestion(
|
||||
@@ -118,24 +124,6 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
/// If the target looks like a partial identifier inside a class declaration
|
||||
/// then return that identifier, otherwise return `null`.
|
||||
SimpleIdentifier _getTargetId(CompletionTarget target) {
|
||||
var node = target.containingNode;
|
||||
if (node is ClassOrMixinDeclaration) {
|
||||
var entity = target.entity;
|
||||
if (entity is FieldDeclaration) {
|
||||
return _getTargetIdFromVarList(entity.fields);
|
||||
}
|
||||
} else if (node is FieldDeclaration) {
|
||||
var entity = target.entity;
|
||||
if (entity is VariableDeclarationList) {
|
||||
return _getTargetIdFromVarList(entity);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
SimpleIdentifier _getTargetIdFromVarList(VariableDeclarationList fields) {
|
||||
var variables = fields.variables;
|
||||
if (variables.length == 1) {
|
||||
@@ -157,6 +145,29 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// If the target looks like a partial identifier inside a class declaration
|
||||
/// then return that identifier [SourceRange], otherwise return `null`.
|
||||
SourceRange _getTargetSourceRange(CompletionTarget target) {
|
||||
var containingNode = target.containingNode;
|
||||
if (containingNode is ClassOrMixinDeclaration) {
|
||||
if (target.entity is FieldDeclaration) {
|
||||
var fieldDecl = target.entity as FieldDeclaration;
|
||||
var simpleIdentifier = _getTargetIdFromVarList(fieldDecl.fields);
|
||||
if (simpleIdentifier != null) {
|
||||
return range.node(simpleIdentifier);
|
||||
}
|
||||
}
|
||||
} else if (containingNode is FieldDeclaration) {
|
||||
if (target.entity is VariableDeclarationList) {
|
||||
var simpleIdentifier = _getTargetIdFromVarList(target.entity);
|
||||
if (simpleIdentifier != null) {
|
||||
return range.node(simpleIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Return `true` if the given [node] has an `override` annotation.
|
||||
bool _hasOverride(AstNode node) {
|
||||
if (node is AnnotatedNode) {
|
||||
@@ -205,4 +216,20 @@ class OverrideContributor implements DartCompletionContributor {
|
||||
nullabilitySuffix: NullabilitySuffix.none,
|
||||
);
|
||||
}
|
||||
|
||||
static bool _inClassMemberBody(AstNode node) {
|
||||
/// TODO(jwren) this method was copied from keyword_contributor.dart, all
|
||||
/// related methods should be moved into a superclass or mixin
|
||||
while (true) {
|
||||
var body = node.thisOrAncestorOfType<FunctionBody>();
|
||||
if (body == null) {
|
||||
return false;
|
||||
}
|
||||
var parent = body.parent;
|
||||
if (parent is ConstructorDeclaration || parent is MethodDeclaration) {
|
||||
return true;
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,6 +285,24 @@ method() {
|
||||
selectionLength: 22);
|
||||
}
|
||||
|
||||
Future<void> test_no_target_inClass_of_interface() async {
|
||||
addTestSource('''
|
||||
class A {
|
||||
void foo() {}
|
||||
}
|
||||
|
||||
class B implements A {
|
||||
^
|
||||
}
|
||||
''');
|
||||
await computeSuggestions();
|
||||
_assertOverride('''
|
||||
@override
|
||||
void foo() {
|
||||
// TODO: implement foo
|
||||
}''', displayText: 'foo() { … }', selectionOffset: 51, selectionLength: 0);
|
||||
}
|
||||
|
||||
Future<void> test_outsideOfWorkspace() async {
|
||||
testFile = convertPath('/home/other/lib/a.dart');
|
||||
addTestSource('''
|
||||
|
||||
Reference in New Issue
Block a user