Include type parameters into suggested code completions.

R=brianwilkerson@google.com

Bug: https://buganizer.corp.google.com/issues/120659839
Change-Id: I51ec6142b97b079c4db55ef1f2081354ee16dda5
Reviewed-on: https://dart-review.googlesource.com/c/91858
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2019-02-04 05:37:37 +00:00 committed by commit-bot@chromium.org
parent 2efd22271e
commit 8c891ec25e
5 changed files with 177 additions and 11 deletions

View file

@ -317,14 +317,30 @@ class _LocalVisitor extends LocalDeclarationVisitor {
}
}
@override
void declaredTypeParameter(TypeParameter node) {
if (optype.includeTypeNameSuggestions) {
_addLocalSuggestion(
null,
node.name,
null,
protocol.ElementKind.TYPE_PARAMETER,
isDeprecated: isDeprecated(node),
kind: CompletionSuggestionKind.IDENTIFIER,
relevance: DART_RELEVANCE_TYPE_PARAMETER,
);
}
}
void _addLocalSuggestion(Comment documentationComment, SimpleIdentifier id,
TypeAnnotation typeName, protocol.ElementKind elemKind,
{bool isAbstract: false,
bool isDeprecated: false,
ClassOrMixinDeclaration classDecl,
CompletionSuggestionKind kind,
FormalParameterList param,
int relevance: DART_RELEVANCE_DEFAULT}) {
CompletionSuggestionKind kind = targetIsFunctionalArgument
kind ??= targetIsFunctionalArgument
? CompletionSuggestionKind.IDENTIFIER
: optype.suggestKind;
CompletionSuggestion suggestion = createLocalSuggestion(

View file

@ -163,19 +163,13 @@ interface A<X> default B<X extends !1List!2> {}''',
<String>["1+DateTime", "2+List"],
failingTests: '12');
buildTests(
'testCommentSnippets030',
'''
buildTests('testCommentSnippets030', '''
class Bar<T extends Foo> {const Bar(!1T!2 k);T!3 m(T!4 a, T!5 b){}final T!6 f = null;}''',
<String>["1+T", "2+T", "3+T", "4+T", "5+T", "6+T"],
failingTests: '123456');
<String>["1+T", "2+T", "3+T", "4+T", "5+T", "6+T"]);
buildTests(
'testCommentSnippets031',
'''
buildTests('testCommentSnippets031', '''
class Bar<T extends Foo> {m(x){if (x is !1) return;if (x is!!!2)}}''',
<String>["1+Bar", "1+T", "2+T", "2+Bar"],
failingTests: '12');
<String>["1+Bar", "1+T", "2+T", "2+Bar"]);
buildTests(
'testCommentSnippets032',

View file

@ -57,6 +57,20 @@ class LocalReferenceContributorTest extends DartCompletionContributorTest {
return cs;
}
CompletionSuggestion assertSuggestTypeParameter(String name,
{int relevance: DART_RELEVANCE_TYPE_PARAMETER}) {
CompletionSuggestion cs = assertSuggest(name,
csKind: CompletionSuggestionKind.IDENTIFIER, relevance: relevance);
expect(cs.returnType, isNull);
Element element = cs.element;
expect(element, isNotNull);
expect(element.kind, equals(ElementKind.TYPE_PARAMETER));
expect(element.name, equals(name));
expect(element.parameters, isNull);
expect(element.returnType, isNull);
return cs;
}
@override
DartCompletionContributor createContributor() {
return new LocalReferenceContributor();
@ -2301,6 +2315,108 @@ main() {
assertSuggestEnumConst('F.four');
}
test_expression_localVariable() async {
addTestSource('''
void f() {
var v = 0;
^
}
''');
await computeSuggestions();
assertSuggestLocalVariable('v', 'int');
}
test_expression_parameter() async {
addTestSource('''
void f(int a) {
^
}
''');
await computeSuggestions();
assertSuggestParameter('a', 'int');
}
test_expression_typeParameter_classDeclaration() async {
addTestSource('''
class A<T> {
void m() {
^
}
}
class B<U> {}
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertNotSuggested('U');
}
test_expression_typeParameter_classTypeAlias() async {
addTestSource('''
class A<U> {}
class B<T> = A<^>;
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertNotSuggested('U');
}
test_expression_typeParameter_functionDeclaration() async {
addTestSource('''
void f<T>() {
^
}
void g<U>() {}
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertNotSuggested('U');
}
test_expression_typeParameter_functionDeclaration_local() async {
addTestSource('''
void f() {
void g2<U>() {}
void g<T>() {
^
}
}
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertNotSuggested('U');
}
test_expression_typeParameter_functionTypeAlias() async {
addTestSource('''
typedef void F<T>(^);
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
}
test_expression_typeParameter_genericTypeAlias() async {
addTestSource('''
typedef F<T> = void Function<U>(^);
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertSuggestTypeParameter('U');
}
test_expression_typeParameter_methodDeclaration() async {
addTestSource('''
class A {
void m<T>() {
^
}
void m2<U>() {}
}
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
assertNotSuggested('U');
}
test_ExpressionStatement_identifier() async {
// SimpleIdentifier ExpressionStatement Block
addSource('/home/test/lib/a.dart', '''
@ -4600,6 +4716,16 @@ class X{}''');
assertNoSuggestions();
}
test_type_typeParameter_classDeclaration() async {
addTestSource('''
class A<T> {
^ m() {}
}
''');
await computeSuggestions();
assertSuggestTypeParameter('T');
}
test_TypeArgumentList() async {
// SimpleIdentifier BinaryExpression ExpressionStatement
addSource('/home/test/lib/a.dart', '''

View file

@ -48,6 +48,8 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
void declaredTopLevelVar(
VariableDeclarationList varList, VariableDeclaration varDecl);
void declaredTypeParameter(TypeParameter node) {}
/**
* Throw an exception indicating that [LocalDeclarationVisitor] should
* stop visiting. This is caught in [visit] which then exits normally.
@ -100,10 +102,15 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
node.declarations.forEach((Declaration declaration) {
if (declaration is ClassDeclaration) {
declaredClass(declaration);
_visitTypeParameters(declaration, declaration.typeParameters);
} else if (declaration is EnumDeclaration) {
declaredEnum(declaration);
} else if (declaration is FunctionDeclaration) {
declaredFunction(declaration);
_visitTypeParameters(
declaration,
declaration.functionExpression.typeParameters,
);
} else if (declaration is TopLevelVariableDeclaration) {
var varList = declaration.variables;
if (varList != null) {
@ -113,10 +120,17 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
}
} else if (declaration is ClassTypeAlias) {
declaredClassTypeAlias(declaration);
_visitTypeParameters(declaration, declaration.typeParameters);
} else if (declaration is FunctionTypeAlias) {
declaredFunctionTypeAlias(declaration);
_visitTypeParameters(declaration, declaration.typeParameters);
} else if (declaration is GenericTypeAlias) {
declaredGenericTypeAlias(declaration);
_visitTypeParameters(declaration, declaration.typeParameters);
_visitTypeParameters(
declaration.functionType,
declaration.functionType.typeParameters,
);
}
});
}
@ -224,6 +238,7 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
});
} else if (member is MethodDeclaration) {
declaredMethod(member);
_visitTypeParameters(member, member.typeParameters);
}
}
}
@ -271,6 +286,10 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
String name = id.name;
if (name != null && name.length > 0) {
declaredFunction(declaration);
_visitTypeParameters(
declaration,
declaration.functionExpression.typeParameters,
);
}
}
}
@ -278,6 +297,16 @@ abstract class LocalDeclarationVisitor extends GeneralizingAstVisitor {
}
}
}
void _visitTypeParameters(AstNode node, TypeParameterList typeParameters) {
if (typeParameters == null) return;
if (node.offset < offset && offset < node.end) {
for (var typeParameter in typeParameters.typeParameters) {
declaredTypeParameter(typeParameter);
}
}
}
}
/**

View file

@ -26,3 +26,4 @@ const int DART_RELEVANCE_LOW = 500;
const int DART_RELEVANCE_NAMED_PARAMETER = 1060;
const int DART_RELEVANCE_NAMED_PARAMETER_REQUIRED = 1065;
const int DART_RELEVANCE_PARAMETER = 1059;
const int DART_RELEVANCE_TYPE_PARAMETER = 1058;